_editor.lua 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359
  1. -- Nvim-Lua stdlib: the `vim` module (:help lua-stdlib)
  2. --
  3. -- Lua code lives in one of four places:
  4. -- 1. Plugins! Not everything needs to live on "vim.*". Plugins are the correct model for
  5. -- non-essential features which the user may want to disable or replace with a third-party
  6. -- plugin. Examples: "editorconfig", "comment".
  7. -- - "opt-out": runtime/plugin/*.lua
  8. -- - "opt-in": runtime/pack/dist/opt/
  9. -- 2. runtime/lua/vim/ (the runtime): Lazy-loaded modules. Examples: `inspect`, `lpeg`.
  10. -- 3. runtime/lua/vim/shared.lua: pure Lua functions which always are available. Used in the test
  11. -- runner, as well as worker threads and processes launched from Nvim.
  12. -- 4. runtime/lua/vim/_editor.lua: Eager-loaded code which directly interacts with the Nvim
  13. -- editor state. Only available in the main thread.
  14. --
  15. -- The top level "vim.*" namespace is for fundamental Lua and editor features. Use submodules for
  16. -- everything else (but avoid excessive "nesting"), or plugins (see above).
  17. --
  18. -- Compatibility with Vim's `if_lua` is explicitly a non-goal.
  19. --
  20. -- Reference (#6580):
  21. -- - https://github.com/luafun/luafun
  22. -- - https://github.com/rxi/lume
  23. -- - http://leafo.net/lapis/reference/utilities.html
  24. -- - https://github.com/bakpakin/Fennel (pretty print, repl)
  25. -- These are for loading runtime modules lazily since they aren't available in
  26. -- the nvim binary as specified in executor.c
  27. for k, v in pairs({
  28. treesitter = true,
  29. filetype = true,
  30. loader = true,
  31. func = true,
  32. F = true,
  33. lsp = true,
  34. hl = true,
  35. diagnostic = true,
  36. keymap = true,
  37. ui = true,
  38. health = true,
  39. secure = true,
  40. snippet = true,
  41. _watch = true,
  42. }) do
  43. vim._submodules[k] = v
  44. end
  45. -- There are things which have special rules in vim._init_packages
  46. -- for legacy reasons (uri) or for performance (_inspector).
  47. -- most new things should go into a submodule namespace ( vim.foobar.do_thing() )
  48. vim._extra = {
  49. uri_from_fname = true,
  50. uri_from_bufnr = true,
  51. uri_to_fname = true,
  52. uri_to_bufnr = true,
  53. show_pos = true,
  54. inspect_pos = true,
  55. }
  56. --- @private
  57. vim.log = {
  58. levels = {
  59. TRACE = 0,
  60. DEBUG = 1,
  61. INFO = 2,
  62. WARN = 3,
  63. ERROR = 4,
  64. OFF = 5,
  65. },
  66. }
  67. local utfs = {
  68. ['utf-8'] = true,
  69. ['utf-16'] = true,
  70. ['utf-32'] = true,
  71. }
  72. -- TODO(lewis6991): document that the signature is system({cmd}, [{opts},] {on_exit})
  73. --- Runs a system command or throws an error if {cmd} cannot be run.
  74. ---
  75. --- Examples:
  76. ---
  77. --- ```lua
  78. --- local on_exit = function(obj)
  79. --- print(obj.code)
  80. --- print(obj.signal)
  81. --- print(obj.stdout)
  82. --- print(obj.stderr)
  83. --- end
  84. ---
  85. --- -- Runs asynchronously:
  86. --- vim.system({'echo', 'hello'}, { text = true }, on_exit)
  87. ---
  88. --- -- Runs synchronously:
  89. --- local obj = vim.system({'echo', 'hello'}, { text = true }):wait()
  90. --- -- { code = 0, signal = 0, stdout = 'hello', stderr = '' }
  91. ---
  92. --- ```
  93. ---
  94. --- See |uv.spawn()| for more details. Note: unlike |uv.spawn()|, vim.system
  95. --- throws an error if {cmd} cannot be run.
  96. ---
  97. --- @param cmd (string[]) Command to execute
  98. --- @param opts vim.SystemOpts? Options:
  99. --- - cwd: (string) Set the current working directory for the sub-process.
  100. --- - env: table<string,string> Set environment variables for the new process. Inherits the
  101. --- current environment with `NVIM` set to |v:servername|.
  102. --- - clear_env: (boolean) `env` defines the job environment exactly, instead of merging current
  103. --- environment.
  104. --- - stdin: (string|string[]|boolean) If `true`, then a pipe to stdin is opened and can be written
  105. --- to via the `write()` method to SystemObj. If string or string[] then will be written to stdin
  106. --- and closed. Defaults to `false`.
  107. --- - stdout: (boolean|function)
  108. --- Handle output from stdout. When passed as a function must have the signature `fun(err: string, data: string)`.
  109. --- Defaults to `true`
  110. --- - stderr: (boolean|function)
  111. --- Handle output from stderr. When passed as a function must have the signature `fun(err: string, data: string)`.
  112. --- Defaults to `true`.
  113. --- - text: (boolean) Handle stdout and stderr as text. Replaces `\r\n` with `\n`.
  114. --- - timeout: (integer) Run the command with a time limit. Upon timeout the process is sent the
  115. --- TERM signal (15) and the exit code is set to 124.
  116. --- - detach: (boolean) If true, spawn the child process in a detached state - this will make it
  117. --- a process group leader, and will effectively enable the child to keep running after the
  118. --- parent exits. Note that the child process will still keep the parent's event loop alive
  119. --- unless the parent process calls |uv.unref()| on the child's process handle.
  120. ---
  121. --- @param on_exit? fun(out: vim.SystemCompleted) Called when subprocess exits. When provided, the command runs
  122. --- asynchronously. Receives SystemCompleted object, see return of SystemObj:wait().
  123. ---
  124. --- @return vim.SystemObj Object with the fields:
  125. --- - cmd (string[]) Command name and args
  126. --- - pid (integer) Process ID
  127. --- - wait (fun(timeout: integer|nil): SystemCompleted) Wait for the process to complete. Upon
  128. --- timeout the process is sent the KILL signal (9) and the exit code is set to 124. Cannot
  129. --- be called in |api-fast|.
  130. --- - SystemCompleted is an object with the fields:
  131. --- - code: (integer)
  132. --- - signal: (integer)
  133. --- - stdout: (string), nil if stdout argument is passed
  134. --- - stderr: (string), nil if stderr argument is passed
  135. --- - kill (fun(signal: integer|string))
  136. --- - write (fun(data: string|nil)) Requires `stdin=true`. Pass `nil` to close the stream.
  137. --- - is_closing (fun(): boolean)
  138. function vim.system(cmd, opts, on_exit)
  139. if type(opts) == 'function' then
  140. on_exit = opts
  141. opts = nil
  142. end
  143. return require('vim._system').run(cmd, opts, on_exit)
  144. end
  145. -- Gets process info from the `ps` command.
  146. -- Used by nvim_get_proc() as a fallback.
  147. function vim._os_proc_info(pid)
  148. if pid == nil or pid <= 0 or type(pid) ~= 'number' then
  149. error('invalid pid')
  150. end
  151. local cmd = { 'ps', '-p', pid, '-o', 'comm=' }
  152. local r = vim.system(cmd):wait()
  153. local name = assert(r.stdout)
  154. if r.code == 1 and vim.trim(name) == '' then
  155. return {} -- Process not found.
  156. elseif r.code ~= 0 then
  157. error('command failed: ' .. vim.fn.string(cmd))
  158. end
  159. local ppid_string = assert(vim.system({ 'ps', '-p', pid, '-o', 'ppid=' }):wait().stdout)
  160. -- Remove trailing whitespace.
  161. name = vim.trim(name):gsub('^.*/', '')
  162. local ppid = tonumber(ppid_string) or -1
  163. return {
  164. name = name,
  165. pid = pid,
  166. ppid = ppid,
  167. }
  168. end
  169. -- Gets process children from the `pgrep` command.
  170. -- Used by nvim_get_proc_children() as a fallback.
  171. function vim._os_proc_children(ppid)
  172. if ppid == nil or ppid <= 0 or type(ppid) ~= 'number' then
  173. error('invalid ppid')
  174. end
  175. local cmd = { 'pgrep', '-P', ppid }
  176. local r = vim.system(cmd):wait()
  177. if r.code == 1 and vim.trim(r.stdout) == '' then
  178. return {} -- Process not found.
  179. elseif r.code ~= 0 then
  180. error('command failed: ' .. vim.fn.string(cmd))
  181. end
  182. local children = {}
  183. for s in r.stdout:gmatch('%S+') do
  184. local i = tonumber(s)
  185. if i ~= nil then
  186. table.insert(children, i)
  187. end
  188. end
  189. return children
  190. end
  191. --- @nodoc
  192. --- @class vim.inspect.Opts
  193. --- @field depth? integer
  194. --- @field newline? string
  195. --- @field process? fun(item:any, path: string[]): any
  196. --- Gets a human-readable representation of the given object.
  197. ---
  198. ---@see |vim.print()|
  199. ---@see https://github.com/kikito/inspect.lua
  200. ---@see https://github.com/mpeterv/vinspect
  201. ---@return string
  202. ---@overload fun(x: any, opts?: vim.inspect.Opts): string
  203. vim.inspect = vim.inspect
  204. do
  205. local tdots, tick, got_line1, undo_started, trailing_nl = 0, 0, false, false, false
  206. --- Paste handler, invoked by |nvim_paste()|.
  207. ---
  208. --- Note: This is provided only as a "hook", don't call it directly; call |nvim_paste()| instead,
  209. --- which arranges redo (dot-repeat) and invokes `vim.paste`.
  210. ---
  211. --- Example: To remove ANSI color codes when pasting:
  212. ---
  213. --- ```lua
  214. --- vim.paste = (function(overridden)
  215. --- return function(lines, phase)
  216. --- for i,line in ipairs(lines) do
  217. --- -- Scrub ANSI color codes from paste input.
  218. --- lines[i] = line:gsub('\27%[[0-9;mK]+', '')
  219. --- end
  220. --- return overridden(lines, phase)
  221. --- end
  222. --- end)(vim.paste)
  223. --- ```
  224. ---
  225. ---@see |paste|
  226. ---
  227. ---@param lines string[] # |readfile()|-style list of lines to paste. |channel-lines|
  228. ---@param phase (-1|1|2|3) -1: "non-streaming" paste: the call contains all lines.
  229. --- If paste is "streamed", `phase` indicates the stream state:
  230. --- - 1: starts the paste (exactly once)
  231. --- - 2: continues the paste (zero or more times)
  232. --- - 3: ends the paste (exactly once)
  233. ---@return boolean result false if client should cancel the paste.
  234. function vim.paste(lines, phase)
  235. local now = vim.uv.now()
  236. local is_first_chunk = phase < 2
  237. local is_last_chunk = phase == -1 or phase == 3
  238. if is_first_chunk then -- Reset flags.
  239. tdots, tick, got_line1, undo_started, trailing_nl = now, 0, false, false, false
  240. end
  241. if #lines == 0 then
  242. lines = { '' }
  243. end
  244. if #lines == 1 and lines[1] == '' and not is_last_chunk then
  245. -- An empty chunk can cause some edge cases in streamed pasting,
  246. -- so don't do anything unless it is the last chunk.
  247. return true
  248. end
  249. -- Note: mode doesn't always start with "c" in cmdline mode, so use getcmdtype() instead.
  250. if vim.fn.getcmdtype() ~= '' then -- cmdline-mode: paste only 1 line.
  251. if not got_line1 then
  252. got_line1 = (#lines > 1)
  253. -- Escape control characters
  254. local line1 = lines[1]:gsub('(%c)', '\022%1')
  255. -- nvim_input() is affected by mappings,
  256. -- so use nvim_feedkeys() with "n" flag to ignore mappings.
  257. -- "t" flag is also needed so the pasted text is saved in cmdline history.
  258. vim.api.nvim_feedkeys(line1, 'nt', true)
  259. end
  260. return true
  261. end
  262. local mode = vim.api.nvim_get_mode().mode
  263. if undo_started then
  264. vim.api.nvim_command('undojoin')
  265. end
  266. if mode:find('^i') or mode:find('^n?t') then -- Insert mode or Terminal buffer
  267. vim.api.nvim_put(lines, 'c', false, true)
  268. elseif phase < 2 and mode:find('^R') and not mode:find('^Rv') then -- Replace mode
  269. -- TODO: implement Replace mode streamed pasting
  270. -- TODO: support Virtual Replace mode
  271. local nchars = 0
  272. for _, line in ipairs(lines) do
  273. nchars = nchars + line:len()
  274. end
  275. --- @type integer, integer
  276. local row, col = unpack(vim.api.nvim_win_get_cursor(0))
  277. local bufline = vim.api.nvim_buf_get_lines(0, row - 1, row, true)[1]
  278. local firstline = lines[1]
  279. firstline = bufline:sub(1, col) .. firstline
  280. lines[1] = firstline
  281. lines[#lines] = lines[#lines] .. bufline:sub(col + nchars + 1, bufline:len())
  282. vim.api.nvim_buf_set_lines(0, row - 1, row, false, lines)
  283. elseif mode:find('^[nvV\22sS\19]') then -- Normal or Visual or Select mode
  284. if mode:find('^n') then -- Normal mode
  285. -- When there was a trailing new line in the previous chunk,
  286. -- the cursor is on the first character of the next line,
  287. -- so paste before the cursor instead of after it.
  288. vim.api.nvim_put(lines, 'c', not trailing_nl, false)
  289. else -- Visual or Select mode
  290. vim.api.nvim_command([[exe "silent normal! \<Del>"]])
  291. local del_start = vim.fn.getpos("'[")
  292. local cursor_pos = vim.fn.getpos('.')
  293. if mode:find('^[VS]') then -- linewise
  294. if cursor_pos[2] < del_start[2] then -- replacing lines at eof
  295. -- create a new line
  296. vim.api.nvim_put({ '' }, 'l', true, true)
  297. end
  298. vim.api.nvim_put(lines, 'c', false, false)
  299. else
  300. -- paste after cursor when replacing text at eol, otherwise paste before cursor
  301. vim.api.nvim_put(lines, 'c', cursor_pos[3] < del_start[3], false)
  302. end
  303. end
  304. -- put cursor at the end of the text instead of one character after it
  305. vim.fn.setpos('.', vim.fn.getpos("']"))
  306. trailing_nl = lines[#lines] == ''
  307. else -- Don't know what to do in other modes
  308. return false
  309. end
  310. undo_started = true
  311. if phase ~= -1 and (now - tdots >= 100) then
  312. local dots = ('.'):rep(tick % 4)
  313. tdots = now
  314. tick = tick + 1
  315. -- Use :echo because Lua print('') is a no-op, and we want to clear the
  316. -- message when there are zero dots.
  317. vim.api.nvim_command(('echo "%s"'):format(dots))
  318. end
  319. if is_last_chunk then
  320. vim.api.nvim_command('redraw' .. (tick > 1 and '|echo ""' or ''))
  321. end
  322. return true -- Paste will not continue if not returning `true`.
  323. end
  324. end
  325. --- Returns a function which calls {fn} via |vim.schedule()|.
  326. ---
  327. --- The returned function passes all arguments to {fn}.
  328. ---
  329. --- Example:
  330. ---
  331. --- ```lua
  332. --- function notify_readable(_err, readable)
  333. --- vim.notify("readable? " .. tostring(readable))
  334. --- end
  335. --- vim.uv.fs_access(vim.fn.stdpath("config"), "R", vim.schedule_wrap(notify_readable))
  336. --- ```
  337. ---
  338. ---@see |lua-loop-callbacks|
  339. ---@see |vim.schedule()|
  340. ---@see |vim.in_fast_event()|
  341. ---@param fn function
  342. ---@return function
  343. function vim.schedule_wrap(fn)
  344. return function(...)
  345. local args = vim.F.pack_len(...)
  346. vim.schedule(function()
  347. fn(vim.F.unpack_len(args))
  348. end)
  349. end
  350. end
  351. -- vim.fn.{func}(...)
  352. ---@nodoc
  353. vim.fn = setmetatable({}, {
  354. --- @param t table<string,function>
  355. --- @param key string
  356. --- @return function
  357. __index = function(t, key)
  358. local _fn --- @type function
  359. if vim.api[key] ~= nil then
  360. _fn = function()
  361. error(string.format('Tried to call API function with vim.fn: use vim.api.%s instead', key))
  362. end
  363. else
  364. _fn = function(...)
  365. return vim.call(key, ...)
  366. end
  367. end
  368. t[key] = _fn
  369. return _fn
  370. end,
  371. })
  372. --- @private
  373. vim.funcref = function(viml_func_name)
  374. return vim.fn[viml_func_name]
  375. end
  376. local VIM_CMD_ARG_MAX = 20
  377. --- Executes Vim script commands.
  378. ---
  379. --- Note that `vim.cmd` can be indexed with a command name to return a callable function to the
  380. --- command.
  381. ---
  382. --- Example:
  383. ---
  384. --- ```lua
  385. --- vim.cmd('echo 42')
  386. --- vim.cmd([[
  387. --- augroup My_group
  388. --- autocmd!
  389. --- autocmd FileType c setlocal cindent
  390. --- augroup END
  391. --- ]])
  392. ---
  393. --- -- Ex command :echo "foo"
  394. --- -- Note string literals need to be double quoted.
  395. --- vim.cmd('echo "foo"')
  396. --- vim.cmd { cmd = 'echo', args = { '"foo"' } }
  397. --- vim.cmd.echo({ args = { '"foo"' } })
  398. --- vim.cmd.echo('"foo"')
  399. ---
  400. --- -- Ex command :write! myfile.txt
  401. --- vim.cmd('write! myfile.txt')
  402. --- vim.cmd { cmd = 'write', args = { "myfile.txt" }, bang = true }
  403. --- vim.cmd.write { args = { "myfile.txt" }, bang = true }
  404. --- vim.cmd.write { "myfile.txt", bang = true }
  405. ---
  406. --- -- Ex command :colorscheme blue
  407. --- vim.cmd('colorscheme blue')
  408. --- vim.cmd.colorscheme('blue')
  409. --- ```
  410. ---
  411. ---@param command string|table Command(s) to execute.
  412. --- If a string, executes multiple lines of Vim script at once. In this
  413. --- case, it is an alias to |nvim_exec2()|, where `opts.output` is set
  414. --- to false. Thus it works identical to |:source|.
  415. --- If a table, executes a single command. In this case, it is an alias
  416. --- to |nvim_cmd()| where `opts` is empty.
  417. ---@see |ex-cmd-index|
  418. vim.cmd = setmetatable({}, {
  419. __call = function(_, command)
  420. if type(command) == 'table' then
  421. return vim.api.nvim_cmd(command, {})
  422. else
  423. vim.api.nvim_exec2(command, {})
  424. return ''
  425. end
  426. end,
  427. __index = function(t, command)
  428. t[command] = function(...)
  429. local opts
  430. if select('#', ...) == 1 and type(select(1, ...)) == 'table' then
  431. opts = select(1, ...)
  432. -- Move indexed positions in opts to opt.args
  433. if opts[1] and not opts.args then
  434. opts.args = {}
  435. for i = 1, VIM_CMD_ARG_MAX do
  436. if not opts[i] then
  437. break
  438. end
  439. opts.args[i] = opts[i]
  440. opts[i] = nil
  441. end
  442. end
  443. else
  444. opts = { args = { ... } }
  445. end
  446. opts.cmd = command
  447. return vim.api.nvim_cmd(opts, {})
  448. end
  449. return t[command]
  450. end,
  451. })
  452. --- @class (private) vim.var_accessor
  453. --- @field [string] any
  454. --- @field [integer] vim.var_accessor
  455. -- These are the vim.env/v/g/o/bo/wo variable magic accessors.
  456. do
  457. --- @param scope string
  458. --- @param handle? false|integer
  459. --- @return vim.var_accessor
  460. local function make_dict_accessor(scope, handle)
  461. vim.validate('scope', scope, 'string')
  462. local mt = {}
  463. function mt:__newindex(k, v)
  464. return vim._setvar(scope, handle or 0, k, v)
  465. end
  466. function mt:__index(k)
  467. if handle == nil and type(k) == 'number' then
  468. return make_dict_accessor(scope, k)
  469. end
  470. return vim._getvar(scope, handle or 0, k)
  471. end
  472. return setmetatable({}, mt)
  473. end
  474. vim.g = make_dict_accessor('g', false)
  475. vim.v = make_dict_accessor('v', false) --[[@as vim.v]]
  476. vim.b = make_dict_accessor('b')
  477. vim.w = make_dict_accessor('w')
  478. vim.t = make_dict_accessor('t')
  479. end
  480. --- @deprecated
  481. --- Gets a dict of line segment ("chunk") positions for the region from `pos1` to `pos2`.
  482. ---
  483. --- Input and output positions are byte positions, (0,0)-indexed. "End of line" column
  484. --- position (for example, |linewise| visual selection) is returned as |v:maxcol| (big number).
  485. ---
  486. ---@param bufnr integer Buffer number, or 0 for current buffer
  487. ---@param pos1 integer[]|string Start of region as a (line, column) tuple or |getpos()|-compatible string
  488. ---@param pos2 integer[]|string End of region as a (line, column) tuple or |getpos()|-compatible string
  489. ---@param regtype string [setreg()]-style selection type
  490. ---@param inclusive boolean Controls whether the ending column is inclusive (see also 'selection').
  491. ---@return table region Dict of the form `{linenr = {startcol,endcol}}`. `endcol` is exclusive, and
  492. ---whole lines are returned as `{startcol,endcol} = {0,-1}`.
  493. function vim.region(bufnr, pos1, pos2, regtype, inclusive)
  494. vim.deprecate('vim.region', 'vim.fn.getregionpos()', '0.13')
  495. if not vim.api.nvim_buf_is_loaded(bufnr) then
  496. vim.fn.bufload(bufnr)
  497. end
  498. if type(pos1) == 'string' then
  499. local pos = vim.fn.getpos(pos1)
  500. pos1 = { pos[2] - 1, pos[3] - 1 }
  501. end
  502. if type(pos2) == 'string' then
  503. local pos = vim.fn.getpos(pos2)
  504. pos2 = { pos[2] - 1, pos[3] - 1 }
  505. end
  506. if pos1[1] > pos2[1] or (pos1[1] == pos2[1] and pos1[2] > pos2[2]) then
  507. pos1, pos2 = pos2, pos1
  508. end
  509. -- getpos() may return {0,0,0,0}
  510. if pos1[1] < 0 or pos1[2] < 0 then
  511. return {}
  512. end
  513. -- check that region falls within current buffer
  514. local buf_line_count = vim.api.nvim_buf_line_count(bufnr)
  515. pos1[1] = math.min(pos1[1], buf_line_count - 1)
  516. pos2[1] = math.min(pos2[1], buf_line_count - 1)
  517. -- in case of block selection, columns need to be adjusted for non-ASCII characters
  518. -- TODO: handle double-width characters
  519. if regtype:byte() == 22 then
  520. local bufline = vim.api.nvim_buf_get_lines(bufnr, pos1[1], pos1[1] + 1, true)[1]
  521. pos1[2] = vim.str_utfindex(bufline, 'utf-32', pos1[2])
  522. end
  523. local region = {}
  524. for l = pos1[1], pos2[1] do
  525. local c1 --- @type number
  526. local c2 --- @type number
  527. if regtype:byte() == 22 then -- block selection: take width from regtype
  528. c1 = pos1[2]
  529. c2 = c1 + tonumber(regtype:sub(2))
  530. -- and adjust for non-ASCII characters
  531. local bufline = vim.api.nvim_buf_get_lines(bufnr, l, l + 1, true)[1]
  532. local utflen = vim.str_utfindex(bufline, 'utf-32', #bufline)
  533. if c1 <= utflen then
  534. c1 = assert(tonumber(vim.str_byteindex(bufline, 'utf-32', c1)))
  535. else
  536. c1 = #bufline + 1
  537. end
  538. if c2 <= utflen then
  539. c2 = assert(tonumber(vim.str_byteindex(bufline, 'utf-32', c2)))
  540. else
  541. c2 = #bufline + 1
  542. end
  543. elseif regtype == 'V' then -- linewise selection, always return whole line
  544. c1 = 0
  545. c2 = -1
  546. else
  547. c1 = (l == pos1[1]) and pos1[2] or 0
  548. if inclusive and l == pos2[1] then
  549. local bufline = vim.api.nvim_buf_get_lines(bufnr, pos2[1], pos2[1] + 1, true)[1]
  550. pos2[2] = vim.fn.byteidx(bufline, vim.fn.charidx(bufline, pos2[2]) + 1)
  551. end
  552. c2 = (l == pos2[1]) and pos2[2] or -1
  553. end
  554. table.insert(region, l, { c1, c2 })
  555. end
  556. return region
  557. end
  558. --- Defers calling {fn} until {timeout} ms passes.
  559. ---
  560. --- Use to do a one-shot timer that calls {fn}
  561. --- Note: The {fn} is |vim.schedule_wrap()|ped automatically, so API functions are
  562. --- safe to call.
  563. ---@param fn function Callback to call once `timeout` expires
  564. ---@param timeout integer Number of milliseconds to wait before calling `fn`
  565. ---@return table timer luv timer object
  566. function vim.defer_fn(fn, timeout)
  567. vim.validate('fn', fn, 'callable', true)
  568. local timer = assert(vim.uv.new_timer())
  569. timer:start(
  570. timeout,
  571. 0,
  572. vim.schedule_wrap(function()
  573. if not timer:is_closing() then
  574. timer:close()
  575. end
  576. fn()
  577. end)
  578. )
  579. return timer
  580. end
  581. --- Displays a notification to the user.
  582. ---
  583. --- This function can be overridden by plugins to display notifications using
  584. --- a custom provider (such as the system notification provider). By default,
  585. --- writes to |:messages|.
  586. ---@param msg string Content of the notification to show to the user.
  587. ---@param level integer|nil One of the values from |vim.log.levels|.
  588. ---@param opts table|nil Optional parameters. Unused by default.
  589. ---@diagnostic disable-next-line: unused-local
  590. function vim.notify(msg, level, opts) -- luacheck: no unused args
  591. if level == vim.log.levels.ERROR then
  592. vim.api.nvim_err_writeln(msg)
  593. elseif level == vim.log.levels.WARN then
  594. vim.api.nvim_echo({ { msg, 'WarningMsg' } }, true, {})
  595. else
  596. vim.api.nvim_echo({ { msg } }, true, {})
  597. end
  598. end
  599. do
  600. local notified = {} --- @type table<string,true>
  601. --- Displays a notification only one time.
  602. ---
  603. --- Like |vim.notify()|, but subsequent calls with the same message will not
  604. --- display a notification.
  605. ---
  606. ---@param msg string Content of the notification to show to the user.
  607. ---@param level integer|nil One of the values from |vim.log.levels|.
  608. ---@param opts table|nil Optional parameters. Unused by default.
  609. ---@return boolean true if message was displayed, else false
  610. function vim.notify_once(msg, level, opts)
  611. if not notified[msg] then
  612. vim.notify(msg, level, opts)
  613. notified[msg] = true
  614. return true
  615. end
  616. return false
  617. end
  618. end
  619. local on_key_cbs = {} --- @type table<integer,[function, table]>
  620. --- Adds Lua function {fn} with namespace id {ns_id} as a listener to every,
  621. --- yes every, input key.
  622. ---
  623. --- The Nvim command-line option |-w| is related but does not support callbacks
  624. --- and cannot be toggled dynamically.
  625. ---
  626. ---@note {fn} will be removed on error.
  627. ---@note {fn} won't be invoked recursively, i.e. if {fn} itself consumes input,
  628. --- it won't be invoked for those keys.
  629. ---@note {fn} will not be cleared by |nvim_buf_clear_namespace()|
  630. ---
  631. ---@param fn nil|fun(key: string, typed: string): string? Function invoked for every input key,
  632. --- after mappings have been applied but before further processing. Arguments
  633. --- {key} and {typed} are raw keycodes, where {key} is the key after mappings
  634. --- are applied, and {typed} is the key(s) before mappings are applied.
  635. --- {typed} may be empty if {key} is produced by non-typed key(s) or by the
  636. --- same typed key(s) that produced a previous {key}.
  637. --- If {fn} returns an empty string, {key} is discarded/ignored.
  638. --- When {fn} is `nil`, the callback associated with namespace {ns_id} is removed.
  639. ---@param ns_id integer? Namespace ID. If nil or 0, generates and returns a
  640. --- new |nvim_create_namespace()| id.
  641. ---@param opts table? Optional parameters
  642. ---
  643. ---@see |keytrans()|
  644. ---
  645. ---@return integer Namespace id associated with {fn}. Or count of all callbacks
  646. ---if on_key() is called without arguments.
  647. function vim.on_key(fn, ns_id, opts)
  648. if fn == nil and ns_id == nil then
  649. return vim.tbl_count(on_key_cbs)
  650. end
  651. vim.validate('fn', fn, 'callable', true)
  652. vim.validate('ns_id', ns_id, 'number', true)
  653. vim.validate('opts', opts, 'table', true)
  654. opts = opts or {}
  655. if ns_id == nil or ns_id == 0 then
  656. ns_id = vim.api.nvim_create_namespace('')
  657. end
  658. on_key_cbs[ns_id] = fn and { fn, opts }
  659. return ns_id
  660. end
  661. --- Executes the on_key callbacks.
  662. ---@private
  663. function vim._on_key(buf, typed_buf)
  664. local failed = {} ---@type [integer, string][]
  665. local discard = false
  666. for k, v in pairs(on_key_cbs) do
  667. local fn = v[1]
  668. local ok, rv = xpcall(function()
  669. return fn(buf, typed_buf)
  670. end, debug.traceback)
  671. if ok and rv ~= nil then
  672. if type(rv) == 'string' and #rv == 0 then
  673. discard = true
  674. -- break -- Without break deliver to all callbacks even when it eventually discards.
  675. -- "break" does not make sense unless callbacks are sorted by ???.
  676. else
  677. ok = false
  678. rv = 'return string must be empty'
  679. end
  680. end
  681. if not ok then
  682. vim.on_key(nil, k)
  683. table.insert(failed, { k, rv })
  684. end
  685. end
  686. if #failed > 0 then
  687. local errmsg = ''
  688. for _, v in ipairs(failed) do
  689. errmsg = errmsg .. string.format('\nWith ns_id %d: %s', v[1], v[2])
  690. end
  691. error(errmsg)
  692. end
  693. return discard
  694. end
  695. --- Convert UTF-32, UTF-16 or UTF-8 {index} to byte index.
  696. --- If {strict_indexing} is false
  697. --- then then an out of range index will return byte length
  698. --- instead of throwing an error.
  699. ---
  700. --- Invalid UTF-8 and NUL is treated like in |vim.str_utfindex()|.
  701. --- An {index} in the middle of a UTF-16 sequence is rounded upwards to
  702. --- the end of that sequence.
  703. ---@param s string
  704. ---@param encoding "utf-8"|"utf-16"|"utf-32"
  705. ---@param index integer
  706. ---@param strict_indexing? boolean # default: true
  707. ---@return integer
  708. function vim.str_byteindex(s, encoding, index, strict_indexing)
  709. if type(encoding) == 'number' then
  710. -- Legacy support for old API
  711. -- Parameters: ~
  712. -- • {str} (`string`)
  713. -- • {index} (`integer`)
  714. -- • {use_utf16} (`boolean?`)
  715. vim.deprecate(
  716. 'vim.str_byteindex',
  717. 'vim.str_byteindex(s, encoding, index, strict_indexing)',
  718. '1.0'
  719. )
  720. local old_index = encoding
  721. local use_utf16 = index or false
  722. return vim._str_byteindex(s, old_index, use_utf16) or error('index out of range')
  723. end
  724. -- Avoid vim.validate for performance.
  725. if type(s) ~= 'string' or type(index) ~= 'number' then
  726. vim.validate('s', s, 'string')
  727. vim.validate('index', index, 'number')
  728. end
  729. local len = #s
  730. if index == 0 or len == 0 then
  731. return 0
  732. end
  733. if not utfs[encoding] then
  734. vim.validate('encoding', encoding, function(v)
  735. return utfs[v], 'invalid encoding'
  736. end)
  737. end
  738. if strict_indexing ~= nil and type(strict_indexing) ~= 'boolean' then
  739. vim.validate('strict_indexing', strict_indexing, 'boolean', true)
  740. end
  741. if strict_indexing == nil then
  742. strict_indexing = true
  743. end
  744. if encoding == 'utf-8' then
  745. if index > len then
  746. return strict_indexing and error('index out of range') or len
  747. end
  748. return index
  749. end
  750. return vim._str_byteindex(s, index, encoding == 'utf-16')
  751. or strict_indexing and error('index out of range')
  752. or len
  753. end
  754. --- Convert byte index to UTF-32, UTF-16 or UTF-8 indices. If {index} is not
  755. --- supplied, the length of the string is used. All indices are zero-based.
  756. ---
  757. --- If {strict_indexing} is false then an out of range index will return string
  758. --- length instead of throwing an error.
  759. --- Invalid UTF-8 bytes, and embedded surrogates are counted as one code point
  760. --- each. An {index} in the middle of a UTF-8 sequence is rounded upwards to the end of
  761. --- that sequence.
  762. ---@param s string
  763. ---@param encoding "utf-8"|"utf-16"|"utf-32"
  764. ---@param index? integer
  765. ---@param strict_indexing? boolean # default: true
  766. ---@return integer
  767. function vim.str_utfindex(s, encoding, index, strict_indexing)
  768. if encoding == nil or type(encoding) == 'number' then
  769. -- Legacy support for old API
  770. -- Parameters: ~
  771. -- • {str} (`string`)
  772. -- • {index} (`integer?`)
  773. vim.deprecate(
  774. 'vim.str_utfindex',
  775. 'vim.str_utfindex(s, encoding, index, strict_indexing)',
  776. '1.0'
  777. )
  778. local old_index = encoding
  779. local col32, col16 = vim._str_utfindex(s, old_index) --[[@as integer,integer]]
  780. if not col32 or not col16 then
  781. error('index out of range')
  782. end
  783. -- Return (multiple): ~
  784. -- (`integer`) UTF-32 index
  785. -- (`integer`) UTF-16 index
  786. return col32, col16
  787. end
  788. if type(s) ~= 'string' or (index ~= nil and type(index) ~= 'number') then
  789. vim.validate('s', s, 'string')
  790. vim.validate('index', index, 'number', true)
  791. end
  792. if not index then
  793. index = math.huge
  794. strict_indexing = false
  795. end
  796. if index == 0 then
  797. return 0
  798. end
  799. if not utfs[encoding] then
  800. vim.validate('encoding', encoding, function(v)
  801. return utfs[v], 'invalid encoding'
  802. end)
  803. end
  804. if strict_indexing ~= nil and type(strict_indexing) ~= 'boolean' then
  805. vim.validate('strict_indexing', strict_indexing, 'boolean', true)
  806. end
  807. if strict_indexing == nil then
  808. strict_indexing = true
  809. end
  810. if encoding == 'utf-8' then
  811. local len = #s
  812. return index <= len and index or (strict_indexing and error('index out of range') or len)
  813. end
  814. local col32, col16 = vim._str_utfindex(s, index) --[[@as integer?,integer?]]
  815. local col = encoding == 'utf-16' and col16 or col32
  816. if col then
  817. return col
  818. end
  819. if strict_indexing then
  820. error('index out of range')
  821. end
  822. local max32, max16 = vim._str_utfindex(s)--[[@as integer integer]]
  823. return encoding == 'utf-16' and max16 or max32
  824. end
  825. --- Generates a list of possible completions for the str
  826. --- String has the pattern.
  827. ---
  828. --- 1. Can we get it to just return things in the global namespace with that name prefix
  829. --- 2. Can we get it to return things from global namespace even with `print(` in front.
  830. ---
  831. --- @param pat string
  832. --- @return any[], integer
  833. function vim._expand_pat(pat, env)
  834. env = env or _G
  835. if pat == '' then
  836. local result = vim.tbl_keys(env)
  837. table.sort(result)
  838. return result, 0
  839. end
  840. -- TODO: We can handle spaces in [] ONLY.
  841. -- We should probably do that at some point, just for cooler completion.
  842. -- TODO: We can suggest the variable names to go in []
  843. -- This would be difficult as well.
  844. -- Probably just need to do a smarter match than just `:match`
  845. -- Get the last part of the pattern
  846. local last_part = pat:match('[%w.:_%[%]\'"]+$')
  847. if not last_part then
  848. return {}, 0
  849. end
  850. local parts, search_index = vim._expand_pat_get_parts(last_part)
  851. local match_part = string.sub(last_part, search_index, #last_part)
  852. local prefix_match_pat = string.sub(pat, 1, #pat - #match_part) or ''
  853. local final_env = env
  854. for _, part in ipairs(parts) do
  855. if type(final_env) ~= 'table' then
  856. return {}, 0
  857. end
  858. local key --- @type any
  859. -- Normally, we just have a string
  860. -- Just attempt to get the string directly from the environment
  861. if type(part) == 'string' then
  862. key = part
  863. else
  864. -- However, sometimes you want to use a variable, and complete on it
  865. -- With this, you have the power.
  866. -- MY_VAR = "api"
  867. -- vim[MY_VAR]
  868. -- -> _G[MY_VAR] -> "api"
  869. local result_key = part[1]
  870. if not result_key then
  871. return {}, 0
  872. end
  873. local result = rawget(env, result_key)
  874. if result == nil then
  875. return {}, 0
  876. end
  877. key = result
  878. end
  879. local field = rawget(final_env, key)
  880. if field == nil then
  881. local mt = getmetatable(final_env)
  882. if mt and type(mt.__index) == 'table' then
  883. field = rawget(mt.__index, key)
  884. elseif final_env == vim and (vim._submodules[key] or vim._extra[key]) then
  885. field = vim[key] --- @type any
  886. end
  887. end
  888. final_env = field
  889. if not final_env then
  890. return {}, 0
  891. end
  892. end
  893. local keys = {} --- @type table<string,true>
  894. --- @param obj table<any,any>
  895. local function insert_keys(obj)
  896. for k, _ in pairs(obj) do
  897. if
  898. type(k) == 'string'
  899. and string.sub(k, 1, string.len(match_part)) == match_part
  900. and k:match('^[_%w]+$') ~= nil -- filter out invalid identifiers for field, e.g. 'foo#bar'
  901. then
  902. keys[k] = true
  903. end
  904. end
  905. end
  906. ---@param acc table<string,any>
  907. local function _fold_to_map(acc, k, v)
  908. acc[k] = (v or true)
  909. return acc
  910. end
  911. if type(final_env) == 'table' then
  912. insert_keys(final_env)
  913. end
  914. local mt = getmetatable(final_env)
  915. if mt and type(mt.__index) == 'table' then
  916. insert_keys(mt.__index)
  917. end
  918. if final_env == vim then
  919. insert_keys(vim._submodules)
  920. insert_keys(vim._extra)
  921. end
  922. -- Completion for dict accessors (special vim variables and vim.fn)
  923. if mt and vim.tbl_contains({ vim.g, vim.t, vim.w, vim.b, vim.v, vim.fn }, final_env) then
  924. local prefix, type = unpack(
  925. vim.fn == final_env and { '', 'function' }
  926. or vim.g == final_env and { 'g:', 'var' }
  927. or vim.t == final_env and { 't:', 'var' }
  928. or vim.w == final_env and { 'w:', 'var' }
  929. or vim.b == final_env and { 'b:', 'var' }
  930. or vim.v == final_env and { 'v:', 'var' }
  931. or { nil, nil }
  932. )
  933. assert(prefix, "Can't resolve final_env")
  934. local vars = vim.fn.getcompletion(prefix .. match_part, type) --- @type string[]
  935. insert_keys(vim
  936. .iter(vars)
  937. :map(function(s) ---@param s string
  938. s = s:gsub('[()]+$', '') -- strip '(' and ')' for function completions
  939. return s:sub(#prefix + 1) -- strip the prefix, e.g., 'g:foo' => 'foo'
  940. end)
  941. :fold({}, _fold_to_map))
  942. end
  943. -- Completion for option accessors (full names only)
  944. if
  945. mt
  946. and vim.tbl_contains(
  947. { vim.o, vim.go, vim.bo, vim.wo, vim.opt, vim.opt_local, vim.opt_global },
  948. final_env
  949. )
  950. then
  951. --- @type fun(option_name: string, option: vim.api.keyset.get_option_info): boolean
  952. local filter = function(_, _)
  953. return true
  954. end
  955. if vim.bo == final_env then
  956. filter = function(_, option)
  957. return option.scope == 'buf'
  958. end
  959. elseif vim.wo == final_env then
  960. filter = function(_, option)
  961. return option.scope == 'win'
  962. end
  963. end
  964. --- @type table<string, vim.api.keyset.get_option_info>
  965. local options = vim.api.nvim_get_all_options_info()
  966. insert_keys(vim.iter(options):filter(filter):fold({}, _fold_to_map))
  967. end
  968. keys = vim.tbl_keys(keys)
  969. table.sort(keys)
  970. return keys, #prefix_match_pat
  971. end
  972. --- @param lua_string string
  973. --- @return (string|string[])[], integer
  974. vim._expand_pat_get_parts = function(lua_string)
  975. local parts = {}
  976. local accumulator, search_index = '', 1
  977. local in_brackets = false
  978. local bracket_end = -1 --- @type integer?
  979. local string_char = nil
  980. for idx = 1, #lua_string do
  981. local s = lua_string:sub(idx, idx)
  982. if not in_brackets and (s == '.' or s == ':') then
  983. table.insert(parts, accumulator)
  984. accumulator = ''
  985. search_index = idx + 1
  986. elseif s == '[' then
  987. in_brackets = true
  988. table.insert(parts, accumulator)
  989. accumulator = ''
  990. search_index = idx + 1
  991. elseif in_brackets then
  992. if idx == bracket_end then
  993. in_brackets = false
  994. search_index = idx + 1
  995. if string_char == 'VAR' then
  996. table.insert(parts, { accumulator })
  997. accumulator = ''
  998. string_char = nil
  999. end
  1000. elseif not string_char then
  1001. bracket_end = string.find(lua_string, ']', idx, true)
  1002. if s == '"' or s == "'" then
  1003. string_char = s
  1004. elseif s ~= ' ' then
  1005. string_char = 'VAR'
  1006. accumulator = s
  1007. end
  1008. elseif string_char then
  1009. if string_char ~= s then
  1010. accumulator = accumulator .. s
  1011. else
  1012. table.insert(parts, accumulator)
  1013. accumulator = ''
  1014. string_char = nil
  1015. end
  1016. end
  1017. else
  1018. accumulator = accumulator .. s
  1019. end
  1020. end
  1021. --- @param val any[]
  1022. parts = vim.tbl_filter(function(val)
  1023. return #val > 0
  1024. end, parts)
  1025. return parts, search_index
  1026. end
  1027. do
  1028. -- Ideally we should just call complete() inside omnifunc, though there are
  1029. -- some bugs, so fake the two-step dance for now.
  1030. local matches --- @type any[]
  1031. --- Omnifunc for completing Lua values from the runtime Lua interpreter,
  1032. --- similar to the builtin completion for the `:lua` command.
  1033. ---
  1034. --- Activate using `set omnifunc=v:lua.vim.lua_omnifunc` in a Lua buffer.
  1035. --- @param find_start 1|0
  1036. function vim.lua_omnifunc(find_start, _)
  1037. if find_start == 1 then
  1038. local line = vim.api.nvim_get_current_line()
  1039. local prefix = string.sub(line, 1, vim.api.nvim_win_get_cursor(0)[2])
  1040. local pos
  1041. matches, pos = vim._expand_pat(prefix)
  1042. return (#matches > 0 and pos) or -1
  1043. else
  1044. return matches
  1045. end
  1046. end
  1047. end
  1048. --- "Pretty prints" the given arguments and returns them unmodified.
  1049. ---
  1050. --- Example:
  1051. ---
  1052. --- ```lua
  1053. --- local hl_normal = vim.print(vim.api.nvim_get_hl(0, { name = 'Normal' }))
  1054. --- ```
  1055. ---
  1056. --- @see |vim.inspect()|
  1057. --- @see |:=|
  1058. --- @param ... any
  1059. --- @return any # given arguments.
  1060. function vim.print(...)
  1061. local msg = {}
  1062. for i = 1, select('#', ...) do
  1063. local o = select(i, ...)
  1064. if type(o) == 'string' then
  1065. table.insert(msg, o)
  1066. else
  1067. table.insert(msg, vim.inspect(o, { newline = '\n', indent = ' ' }))
  1068. end
  1069. end
  1070. print(table.concat(msg, '\n'))
  1071. return ...
  1072. end
  1073. --- Translates keycodes.
  1074. ---
  1075. --- Example:
  1076. ---
  1077. --- ```lua
  1078. --- local k = vim.keycode
  1079. --- vim.g.mapleader = k'<bs>'
  1080. --- ```
  1081. ---
  1082. --- @param str string String to be converted.
  1083. --- @return string
  1084. --- @see |nvim_replace_termcodes()|
  1085. function vim.keycode(str)
  1086. return vim.api.nvim_replace_termcodes(str, true, true, true)
  1087. end
  1088. --- @param server_addr string
  1089. --- @param connect_error string
  1090. function vim._cs_remote(rcid, server_addr, connect_error, args)
  1091. --- @return string
  1092. local function connection_failure_errmsg(consequence)
  1093. local explanation --- @type string
  1094. if server_addr == '' then
  1095. explanation = 'No server specified with --server'
  1096. else
  1097. explanation = "Failed to connect to '" .. server_addr .. "'"
  1098. if connect_error ~= '' then
  1099. explanation = explanation .. ': ' .. connect_error
  1100. end
  1101. end
  1102. return 'E247: ' .. explanation .. '. ' .. consequence
  1103. end
  1104. local f_silent = false
  1105. local f_tab = false
  1106. local subcmd = string.sub(args[1], 10)
  1107. if subcmd == 'tab' then
  1108. f_tab = true
  1109. elseif subcmd == 'silent' then
  1110. f_silent = true
  1111. elseif
  1112. subcmd == 'wait'
  1113. or subcmd == 'wait-silent'
  1114. or subcmd == 'tab-wait'
  1115. or subcmd == 'tab-wait-silent'
  1116. then
  1117. return { errmsg = 'E5600: Wait commands not yet implemented in Nvim' }
  1118. elseif subcmd == 'tab-silent' then
  1119. f_tab = true
  1120. f_silent = true
  1121. elseif subcmd == 'send' then
  1122. if rcid == 0 then
  1123. return { errmsg = connection_failure_errmsg('Send failed.') }
  1124. end
  1125. vim.rpcrequest(rcid, 'nvim_input', args[2])
  1126. return { should_exit = true, tabbed = false }
  1127. elseif subcmd == 'expr' then
  1128. if rcid == 0 then
  1129. return { errmsg = connection_failure_errmsg('Send expression failed.') }
  1130. end
  1131. local res = tostring(vim.rpcrequest(rcid, 'nvim_eval', args[2]))
  1132. return { result = res, should_exit = true, tabbed = false }
  1133. elseif subcmd ~= '' then
  1134. return { errmsg = 'Unknown option argument: ' .. tostring(args[1]) }
  1135. end
  1136. if rcid == 0 then
  1137. if not f_silent then
  1138. vim.notify(connection_failure_errmsg('Editing locally'), vim.log.levels.WARN)
  1139. end
  1140. else
  1141. local command = {}
  1142. if f_tab then
  1143. table.insert(command, 'tab')
  1144. end
  1145. table.insert(command, 'drop')
  1146. for i = 2, #args do
  1147. table.insert(command, vim.fn.fnameescape(args[i]))
  1148. end
  1149. vim.fn.rpcrequest(rcid, 'nvim_command', table.concat(command, ' '))
  1150. end
  1151. return {
  1152. should_exit = rcid ~= 0,
  1153. tabbed = f_tab,
  1154. }
  1155. end
  1156. do
  1157. local function truncated_echo(msg)
  1158. -- Truncate message to avoid hit-enter-prompt
  1159. local max_width = vim.o.columns * math.max(vim.o.cmdheight - 1, 0) + vim.v.echospace
  1160. local msg_truncated = string.sub(msg, 1, max_width)
  1161. vim.api.nvim_echo({ { msg_truncated, 'WarningMsg' } }, true, {})
  1162. end
  1163. local notified = false
  1164. function vim._truncated_echo_once(msg)
  1165. if not notified then
  1166. truncated_echo(msg)
  1167. notified = true
  1168. return true
  1169. end
  1170. return false
  1171. end
  1172. end
  1173. --- This is basically the same as debug.traceback(), except the full paths are shown.
  1174. local function traceback()
  1175. local level = 4
  1176. local backtrace = { 'stack traceback:' }
  1177. while true do
  1178. local info = debug.getinfo(level, 'Sl')
  1179. if not info then
  1180. break
  1181. end
  1182. local msg = (' %s:%s'):format(info.source:sub(2), info.currentline)
  1183. table.insert(backtrace, msg)
  1184. level = level + 1
  1185. end
  1186. return table.concat(backtrace, '\n')
  1187. end
  1188. --- Shows a deprecation message to the user.
  1189. ---
  1190. ---@param name string Deprecated feature (function, API, etc.).
  1191. ---@param alternative string|nil Suggested alternative feature.
  1192. ---@param version string Version when the deprecated function will be removed.
  1193. ---@param plugin string|nil Name of the plugin that owns the deprecated feature.
  1194. --- Defaults to "Nvim".
  1195. ---@param backtrace boolean|nil Prints backtrace. Defaults to true.
  1196. ---
  1197. ---@return string|nil # Deprecated message, or nil if no message was shown.
  1198. function vim.deprecate(name, alternative, version, plugin, backtrace)
  1199. plugin = plugin or 'Nvim'
  1200. if plugin == 'Nvim' then
  1201. require('vim.deprecated.health').add(name, version, traceback(), alternative)
  1202. -- Show a warning only if feature is hard-deprecated (see MAINTAIN.md).
  1203. -- Example: if removal `version` is 0.12 (soft-deprecated since 0.10-dev), show warnings
  1204. -- starting at 0.11, including 0.11-dev.
  1205. local major, minor = version:match('(%d+)%.(%d+)')
  1206. major, minor = tonumber(major), tonumber(minor)
  1207. local nvim_major = 0 --- Current Nvim major version.
  1208. -- We can't "subtract" from a major version, so:
  1209. -- * Always treat `major > nvim_major` as soft-deprecation.
  1210. -- * Compare `minor - 1` if `major == nvim_major`.
  1211. if major > nvim_major then
  1212. return -- Always soft-deprecation (see MAINTAIN.md).
  1213. end
  1214. local hard_deprecated_since = string.format('nvim-%d.%d', major, minor - 1)
  1215. if major == nvim_major and vim.fn.has(hard_deprecated_since) == 0 then
  1216. return
  1217. end
  1218. local msg = ('%s is deprecated. Run ":checkhealth vim.deprecated" for more information'):format(
  1219. name
  1220. )
  1221. local displayed = vim._truncated_echo_once(msg)
  1222. return displayed and msg or nil
  1223. else
  1224. vim.validate('name', name, 'string')
  1225. vim.validate('alternative', alternative, 'string', true)
  1226. vim.validate('version', version, 'string', true)
  1227. vim.validate('plugin', plugin, 'string', true)
  1228. local msg = ('%s is deprecated'):format(name)
  1229. msg = alternative and ('%s, use %s instead.'):format(msg, alternative) or (msg .. '.')
  1230. msg = ('%s\nFeature will be removed in %s %s'):format(msg, plugin, version)
  1231. local displayed = vim.notify_once(msg, vim.log.levels.WARN)
  1232. if displayed and backtrace ~= false then
  1233. vim.notify(debug.traceback('', 2):sub(2), vim.log.levels.WARN)
  1234. end
  1235. return displayed and msg or nil
  1236. end
  1237. end
  1238. require('vim._options')
  1239. -- Remove at Nvim 1.0
  1240. ---@deprecated
  1241. vim.loop = vim.uv
  1242. -- Deprecated. Remove at Nvim 2.0
  1243. vim.highlight = vim._defer_deprecated_module('vim.highlight', 'vim.hl')
  1244. return vim