mirror of
https://github.com/neovim/neovim.git
synced 2024-12-23 20:55:18 -07:00
d9d890562e
ref #24572
651 lines
15 KiB
Lua
651 lines
15 KiB
Lua
-------------------------------------------------------------------------------
|
|
-- This file is auto generated by vim9jit. Do not edit by hand.
|
|
-- All content is in the source repository.
|
|
-- Bugs should be reported to: github.com/tjdevries/vim9jit
|
|
--
|
|
-- In addition, this file is considered "private" by neovim. You should
|
|
-- not expect any of the APIs, functions, etc to be stable. They are subject
|
|
-- to change at any time.
|
|
-------------------------------------------------------------------------------
|
|
|
|
local vim9 = (function()
|
|
local M = {}
|
|
|
|
M.ternary = function(cond, if_true, if_false)
|
|
if cond then
|
|
if type(if_true) == 'function' then
|
|
return if_true()
|
|
else
|
|
return if_true
|
|
end
|
|
else
|
|
if type(if_false) == 'function' then
|
|
return if_false()
|
|
else
|
|
return if_false
|
|
end
|
|
end
|
|
end
|
|
|
|
M.fn_ref = function(module, name, copied, ...)
|
|
for _, val in ipairs({ ... }) do
|
|
table.insert(copied, val)
|
|
end
|
|
|
|
local funcref = name
|
|
if type(funcref) == 'function' then
|
|
return funcref(unpack(copied))
|
|
elseif type(funcref) == 'string' then
|
|
if vim.fn.exists('*' .. funcref) == 1 then
|
|
return vim.fn[funcref](unpack(copied))
|
|
end
|
|
|
|
if module[funcref] then
|
|
module[funcref](unpack(copied))
|
|
end
|
|
|
|
error('unknown function: ' .. funcref)
|
|
else
|
|
error(string.format('unable to call funcref: %s', funcref))
|
|
end
|
|
end
|
|
|
|
M.fn_mut = function(name, args, info)
|
|
local result = vim.fn._Vim9ScriptFn(name, args)
|
|
for idx, val in pairs(result[2]) do
|
|
M.replace(args[idx], val)
|
|
end
|
|
|
|
-- Substitute returning the reference to the
|
|
-- returned value
|
|
if info.replace then
|
|
return args[info.replace + 1]
|
|
end
|
|
|
|
return result[1]
|
|
end
|
|
|
|
M.replace = function(orig, new)
|
|
if type(orig) == 'table' and type(new) == 'table' then
|
|
for k in pairs(orig) do
|
|
orig[k] = nil
|
|
end
|
|
|
|
for k, v in pairs(new) do
|
|
orig[k] = v
|
|
end
|
|
|
|
return orig
|
|
end
|
|
|
|
return new
|
|
end
|
|
|
|
M.index = function(obj, idx)
|
|
if vim.islist(obj) then
|
|
if idx < 0 then
|
|
return obj[#obj + idx + 1]
|
|
else
|
|
return obj[idx + 1]
|
|
end
|
|
elseif type(obj) == 'table' then
|
|
return obj[idx]
|
|
elseif type(obj) == 'string' then
|
|
return string.sub(obj, idx + 1, idx + 1)
|
|
end
|
|
|
|
error('invalid type for indexing: ' .. vim.inspect(obj))
|
|
end
|
|
|
|
M.index_expr = function(idx)
|
|
if type(idx) == 'string' then
|
|
return idx
|
|
elseif type(idx) == 'number' then
|
|
return idx + 1
|
|
else
|
|
error(string.format('not yet handled: %s', vim.inspect(idx)))
|
|
end
|
|
end
|
|
|
|
M.slice = function(obj, start, finish)
|
|
if start == nil then
|
|
start = 0
|
|
end
|
|
|
|
if start < 0 then
|
|
start = #obj + start
|
|
end
|
|
assert(type(start) == 'number')
|
|
|
|
if finish == nil then
|
|
finish = #obj
|
|
end
|
|
|
|
if finish < 0 then
|
|
finish = #obj + finish
|
|
end
|
|
assert(type(finish) == 'number')
|
|
|
|
local slicer
|
|
if vim.islist(obj) then
|
|
slicer = vim.list_slice
|
|
elseif type(obj) == 'string' then
|
|
slicer = string.sub
|
|
else
|
|
error('invalid type for slicing: ' .. vim.inspect(obj))
|
|
end
|
|
|
|
return slicer(obj, start + 1, finish + 1)
|
|
end
|
|
|
|
-- Currently unused, but this could be used to embed vim9jit within a
|
|
-- running nvim application and transpile "on the fly" as files are
|
|
-- sourced. There would still need to be some work done to make that
|
|
-- work correctly with imports and what not, but overall it could
|
|
-- work well for calling ":source X" from within a vimscript/vim9script
|
|
-- function
|
|
M.make_source_cmd = function()
|
|
local group = vim.api.nvim_create_augroup('vim9script-source', {})
|
|
vim.api.nvim_create_autocmd('SourceCmd', {
|
|
pattern = '*.vim',
|
|
group = group,
|
|
callback = function(a)
|
|
local file = vim.fn.readfile(a.file)
|
|
for _, line in ipairs(file) do
|
|
-- TODO: Or starts with def <something>
|
|
-- You can use def in legacy vim files
|
|
if vim.startswith(line, 'vim9script') then
|
|
-- TODO: Use the rust lib to actually
|
|
-- generate the corresponding lua code and then
|
|
-- execute that (instead of sourcing it directly)
|
|
return
|
|
end
|
|
end
|
|
|
|
vim.api.nvim_exec2(table.concat(file, '\n'), { output = false })
|
|
end,
|
|
})
|
|
end
|
|
|
|
M.iter = function(expr)
|
|
if vim.islist(expr) then
|
|
return ipairs(expr)
|
|
else
|
|
return pairs(expr)
|
|
end
|
|
end
|
|
|
|
M.ITER_DEFAULT = 0
|
|
M.ITER_CONTINUE = 1
|
|
M.ITER_BREAK = 2
|
|
M.ITER_RETURN = 3
|
|
|
|
return M
|
|
end)()
|
|
|
|
vim.cmd([[
|
|
function! _Vim9ScriptFn(name, args) abort
|
|
try
|
|
let ret = function(a:name, a:args)()
|
|
catch
|
|
echo "Failed..."
|
|
echo a:name
|
|
echo a:args
|
|
|
|
throw v:errmsg
|
|
endtry
|
|
|
|
return [ret, a:args]
|
|
endfunction
|
|
]])
|
|
|
|
vim9['autoload'] = (function()
|
|
return function(path)
|
|
return loadfile(path)()
|
|
end
|
|
end)()
|
|
vim9['bool'] = (function()
|
|
return function(...)
|
|
return vim9.convert.to_vim_bool(...)
|
|
end
|
|
end)()
|
|
vim9['convert'] = (function()
|
|
local M = {}
|
|
|
|
M.decl_bool = function(val)
|
|
if type(val) == 'boolean' then
|
|
return val
|
|
elseif type(val) == 'number' then
|
|
if val == 0 then
|
|
return false
|
|
elseif val == 1 then
|
|
return true
|
|
else
|
|
error(string.format('bad number passed to bool declaration: %s', val))
|
|
end
|
|
end
|
|
|
|
error(string.format('invalid bool declaration: %s', vim.inspect(val)))
|
|
end
|
|
|
|
M.decl_dict = function(val)
|
|
if type(val) == 'nil' then
|
|
return vim.empty_dict()
|
|
elseif type(val) == 'table' then
|
|
if vim.tbl_isempty(val) then
|
|
return vim.empty_dict()
|
|
elseif vim.islist(val) then
|
|
error(string.format('Cannot pass list to dictionary? %s', vim.inspect(val)))
|
|
else
|
|
return val
|
|
end
|
|
end
|
|
|
|
error(string.format('invalid dict declaration: %s', vim.inspect(val)))
|
|
end
|
|
|
|
M.to_vim_bool = function(val)
|
|
if type(val) == 'boolean' then
|
|
return val
|
|
elseif type(val) == 'number' then
|
|
return val ~= 0
|
|
elseif type(val) == 'string' then
|
|
return string.len(val) ~= 0
|
|
elseif type(val) == 'table' then
|
|
return not vim.tbl_isempty(val)
|
|
elseif val == nil then
|
|
return false
|
|
end
|
|
|
|
error('unhandled type: ' .. vim.inspect(val))
|
|
end
|
|
|
|
return M
|
|
end)()
|
|
vim9['fn'] = (function()
|
|
local M = {}
|
|
|
|
M.insert = function(list, item, idx)
|
|
if idx == nil then
|
|
idx = 1
|
|
end
|
|
|
|
table.insert(list, idx + 1, item)
|
|
|
|
return list
|
|
end
|
|
|
|
M.extend = function(left, right, expr3)
|
|
if expr3 ~= nil then
|
|
error("haven't written this code yet")
|
|
end
|
|
|
|
if vim.islist(right) then
|
|
vim.list_extend(left, right)
|
|
return left
|
|
else
|
|
-- local result = vim.tbl_extend(left, right)
|
|
for k, v in pairs(right) do
|
|
left[k] = v
|
|
end
|
|
|
|
return left
|
|
end
|
|
end
|
|
|
|
M.add = function(list, item)
|
|
table.insert(list, item)
|
|
return list
|
|
end
|
|
|
|
M.has_key = function(obj, key)
|
|
return not not obj[key]
|
|
end
|
|
|
|
M.prop_type_add = function(...)
|
|
local args = { ... }
|
|
print('[prop_type_add]', vim.inspect(args))
|
|
end
|
|
|
|
do
|
|
local has_overrides = {
|
|
-- We do have vim9script ;) that's this plugin
|
|
['vim9script'] = true,
|
|
|
|
-- Include some vim patches that are sometimes required by various vim9script plugins
|
|
-- that we implement via vim9jit
|
|
[ [[patch-8.2.2261]] ] = true,
|
|
[ [[patch-8.2.4257]] ] = true,
|
|
}
|
|
|
|
M.has = function(patch)
|
|
if has_overrides[patch] then
|
|
return true
|
|
end
|
|
|
|
return vim.fn.has(patch)
|
|
end
|
|
end
|
|
|
|
--[=[
|
|
Currently missing patch, can be removed in the future.
|
|
|
|
readdirex({directory} [, {expr} [, {dict}]]) *readdirex()*
|
|
Extended version of |readdir()|.
|
|
Return a list of Dictionaries with file and directory
|
|
information in {directory}.
|
|
This is useful if you want to get the attributes of file and
|
|
directory at the same time as getting a list of a directory.
|
|
This is much faster than calling |readdir()| then calling
|
|
|getfperm()|, |getfsize()|, |getftime()| and |getftype()| for
|
|
each file and directory especially on MS-Windows.
|
|
The list will by default be sorted by name (case sensitive),
|
|
the sorting can be changed by using the optional {dict}
|
|
argument, see |readdir()|.
|
|
|
|
The Dictionary for file and directory information has the
|
|
following items:
|
|
group Group name of the entry. (Only on Unix)
|
|
name Name of the entry.
|
|
perm Permissions of the entry. See |getfperm()|.
|
|
size Size of the entry. See |getfsize()|.
|
|
time Timestamp of the entry. See |getftime()|.
|
|
type Type of the entry.
|
|
On Unix, almost same as |getftype()| except:
|
|
Symlink to a dir "linkd"
|
|
Other symlink "link"
|
|
On MS-Windows:
|
|
Normal file "file"
|
|
Directory "dir"
|
|
Junction "junction"
|
|
Symlink to a dir "linkd"
|
|
Other symlink "link"
|
|
Other reparse point "reparse"
|
|
user User name of the entry's owner. (Only on Unix)
|
|
On Unix, if the entry is a symlink, the Dictionary includes
|
|
the information of the target (except the "type" item).
|
|
On MS-Windows, it includes the information of the symlink
|
|
itself because of performance reasons.
|
|
--]=]
|
|
M.readdirex = function(dir)
|
|
local files = vim.fn.readdir(dir)
|
|
local direx = {}
|
|
for _, f in ipairs(files) do
|
|
table.insert(direx, {
|
|
name = f,
|
|
type = vim.fn.getftype(f),
|
|
})
|
|
end
|
|
|
|
return direx
|
|
end
|
|
|
|
M.mapnew = function(tbl, expr)
|
|
return vim.fn.map(tbl, expr)
|
|
end
|
|
|
|
M.typename = function(val)
|
|
local ty = type(val)
|
|
if ty == 'string' then
|
|
return 'string'
|
|
elseif ty == 'boolean' then
|
|
return 'bool'
|
|
elseif ty == 'number' then
|
|
return 'number'
|
|
else
|
|
error(string.format('typename: %s', val))
|
|
end
|
|
end
|
|
|
|
-- Popup menu stuff: Could be rolled into other plugin later
|
|
-- but currently is here for testing purposes (and implements
|
|
-- some very simple compat layers at the moment)
|
|
do
|
|
local pos_map = {
|
|
topleft = 'NW',
|
|
topright = 'NE',
|
|
botleft = 'SW',
|
|
botright = 'SE',
|
|
}
|
|
|
|
M.popup_menu = function(_, options)
|
|
-- print "OPTIONS:"
|
|
|
|
local buf = vim.api.nvim_create_buf(false, true)
|
|
local win = vim.api.nvim_open_win(buf, true, {
|
|
relative = 'editor',
|
|
style = 'minimal',
|
|
anchor = pos_map[options.pos],
|
|
height = options.maxheight or options.minheight,
|
|
width = options.maxwidth or options.minwidth,
|
|
row = options.line,
|
|
col = options.col,
|
|
})
|
|
|
|
if options.filter then
|
|
local loop
|
|
loop = function()
|
|
vim.cmd([[redraw!]])
|
|
local ok, ch = pcall(vim.fn.getcharstr)
|
|
if not ok then
|
|
return
|
|
end -- interrupted
|
|
|
|
if ch == '<C-C>' then
|
|
return
|
|
end
|
|
|
|
if not require('vim9script').bool(options.filter(nil, ch)) then
|
|
vim.cmd.normal(ch)
|
|
end
|
|
|
|
vim.schedule(loop)
|
|
end
|
|
|
|
vim.schedule(loop)
|
|
end
|
|
|
|
return win
|
|
end
|
|
|
|
M.popup_settext = function(id, text)
|
|
if type(text) == 'string' then
|
|
-- text = vim.split(text, "\n")
|
|
error("Haven't handled string yet")
|
|
end
|
|
|
|
local lines = {}
|
|
for _, obj in ipairs(text) do
|
|
table.insert(lines, obj.text)
|
|
end
|
|
|
|
vim.api.nvim_buf_set_lines(vim.api.nvim_win_get_buf(id), 0, -1, false, lines)
|
|
end
|
|
|
|
M.popup_filter_menu = function()
|
|
print('ok, just pretend we filtered the menu')
|
|
end
|
|
|
|
M.popup_setoptions = function(id, _)
|
|
print('setting options...', id)
|
|
end
|
|
end
|
|
|
|
M = setmetatable(M, {
|
|
__index = vim.fn,
|
|
})
|
|
|
|
return M
|
|
end)()
|
|
vim9['heredoc'] = (function()
|
|
local M = {}
|
|
|
|
M.trim = function(lines)
|
|
local min_whitespace = 9999
|
|
for _, line in ipairs(lines) do
|
|
local _, finish = string.find(line, '^%s*')
|
|
min_whitespace = math.min(min_whitespace, finish)
|
|
end
|
|
|
|
local trimmed_lines = {}
|
|
for _, line in ipairs(lines) do
|
|
table.insert(trimmed_lines, string.sub(line, min_whitespace + 1))
|
|
end
|
|
|
|
return trimmed_lines
|
|
end
|
|
|
|
return M
|
|
end)()
|
|
vim9['import'] = (function()
|
|
local imported = {}
|
|
imported.autoload = setmetatable({}, {
|
|
__index = function(_, name)
|
|
local luaname = 'autoload/' .. string.gsub(name, '%.vim$', '.lua')
|
|
local runtime_file = vim.api.nvim_get_runtime_file(luaname, false)[1]
|
|
if not runtime_file then
|
|
error('unable to find autoload file:' .. name)
|
|
end
|
|
|
|
return imported.absolute[vim.fn.fnamemodify(runtime_file, ':p')]
|
|
end,
|
|
})
|
|
|
|
imported.absolute = setmetatable({}, {
|
|
__index = function(self, name)
|
|
if vim.uv.fs_stat(name) then
|
|
local result = loadfile(name)()
|
|
rawset(self, name, result)
|
|
|
|
return result
|
|
end
|
|
|
|
error(string.format('unabled to find absolute file: %s', name))
|
|
end,
|
|
})
|
|
|
|
return function(info)
|
|
local name = info.name
|
|
|
|
if info.autoload then
|
|
return imported.autoload[info.name]
|
|
end
|
|
|
|
local debug_info = debug.getinfo(2, 'S')
|
|
local sourcing_path = vim.fn.fnamemodify(string.sub(debug_info.source, 2), ':p')
|
|
|
|
-- Relative paths
|
|
if vim.startswith(name, '../') or vim.startswith(name, './') then
|
|
local luaname = string.gsub(name, '%.vim$', '.lua')
|
|
local directory = vim.fn.fnamemodify(sourcing_path, ':h')
|
|
local search = directory .. '/' .. luaname
|
|
return imported.absolute[search]
|
|
end
|
|
|
|
if vim.startswith(name, '/') then
|
|
error('absolute path')
|
|
-- local luaname = string.gsub(name, "%.vim", ".lua")
|
|
-- local runtime_file = vim.api.nvim_get_runtime_file(luaname, false)[1]
|
|
-- if runtime_file then
|
|
-- runtime_file = vim.fn.fnamemodify(runtime_file, ":p")
|
|
-- return loadfile(runtime_file)()
|
|
-- end
|
|
end
|
|
|
|
error('Unhandled case' .. vim.inspect(info) .. vim.inspect(debug_info))
|
|
end
|
|
end)()
|
|
vim9['ops'] = (function()
|
|
local lib = vim9
|
|
|
|
local M = {}
|
|
|
|
M['And'] = function(left, right)
|
|
return lib.bool(left) and lib.bool(right)
|
|
end
|
|
|
|
M['Or'] = function(left, right)
|
|
return lib.bool(left) or lib.bool(right)
|
|
end
|
|
|
|
M['Plus'] = function(left, right)
|
|
return left + right
|
|
end
|
|
|
|
M['Multiply'] = function(left, right)
|
|
return left * right
|
|
end
|
|
|
|
M['Divide'] = function(left, right)
|
|
return left / right
|
|
end
|
|
|
|
M['StringConcat'] = function(left, right)
|
|
return left .. right
|
|
end
|
|
|
|
M['EqualTo'] = function(left, right)
|
|
return left == right
|
|
end
|
|
|
|
M['NotEqualTo'] = function(left, right)
|
|
return not M['EqualTo'](left, right)
|
|
end
|
|
|
|
M['LessThan'] = function(left, right)
|
|
return left < right
|
|
end
|
|
|
|
M['LessThanOrEqual'] = function(left, right)
|
|
return left <= right
|
|
end
|
|
|
|
M['GreaterThan'] = function(left, right)
|
|
return left > right
|
|
end
|
|
|
|
M['GreaterThanOrEqual'] = function(left, right)
|
|
return left >= right
|
|
end
|
|
|
|
M['RegexpMatches'] = function(left, right)
|
|
return not not vim.regex(right):match_str(left)
|
|
end
|
|
|
|
M['RegexpMatchesIns'] = function(left, right)
|
|
return not not vim.regex('\\c' .. right):match_str(left)
|
|
end
|
|
|
|
M['NotRegexpMatches'] = function(left, right)
|
|
return not M['RegexpMatches'](left, right)
|
|
end
|
|
|
|
M['Modulo'] = function(left, right)
|
|
return left % right
|
|
end
|
|
|
|
M['Minus'] = function(left, right)
|
|
-- TODO: This is not right :)
|
|
return left - right
|
|
end
|
|
|
|
return M
|
|
end)()
|
|
vim9['prefix'] = (function()
|
|
local lib = vim9
|
|
|
|
local M = {}
|
|
|
|
M['Minus'] = function(right)
|
|
return -right
|
|
end
|
|
|
|
M['Bang'] = function(right)
|
|
return not lib.bool(right)
|
|
end
|
|
|
|
return M
|
|
end)()
|
|
|
|
return vim9
|