Regenerate nvim config
This commit is contained in:
@ -0,0 +1,261 @@
|
||||
---@class LuaParam
|
||||
---@field name? string
|
||||
---@field type? string
|
||||
---@field doc? string
|
||||
---@field optional? boolean
|
||||
|
||||
--- @class LuaFunction
|
||||
--- @field name string,
|
||||
--- @field doc string,
|
||||
--- @field deprecated? boolean
|
||||
--- @field overload? string[]
|
||||
--- @field params LuaParam[]
|
||||
--- @field return LuaParam[]
|
||||
|
||||
local M = {}
|
||||
|
||||
M.name2type = {
|
||||
boolean = { "set" },
|
||||
buffer = { "buffer", "bufid", "bufnr", "buf" },
|
||||
window = { "win", "window", "winid", "winnr" },
|
||||
number = { "col", "lnum", "tabnr", "nr", "pos", "ns", "index", "from", "to", "start", "stop", "end_", "integer" },
|
||||
string = { "str", "text", "string" },
|
||||
["table<string, any>"] = { "opt", "opts", "options", "dict", "dictionary" },
|
||||
["fun()"] = { "fn", "function", "callback", "func", "funcref", "luaref" },
|
||||
["any[]"] = { "args", "list", "array" },
|
||||
["nil"] = { "void", "none" },
|
||||
}
|
||||
M.keywords =
|
||||
{ "or", "and", "repeat", "function", "end", "return", "do", "break", "else", "elseif", "for", "goto", "if", "while" }
|
||||
M.nvim_types = {
|
||||
window = "integer",
|
||||
buffer = "integer",
|
||||
tabpage = "integer",
|
||||
job = "number",
|
||||
channel = "integer",
|
||||
sends = "number",
|
||||
blob = "number",
|
||||
object = "any",
|
||||
float = "number",
|
||||
}
|
||||
M.lua_types = {
|
||||
["nil"] = "nil",
|
||||
number = "number",
|
||||
string = "string",
|
||||
boolean = "boolean",
|
||||
["function"] = "fun()",
|
||||
table = "table",
|
||||
}
|
||||
|
||||
function M.is_keyword(str)
|
||||
return vim.tbl_contains(M.keywords, str)
|
||||
end
|
||||
|
||||
---@param str string
|
||||
---@param first? string
|
||||
function M.comment(str, first)
|
||||
first = first or ""
|
||||
local prefix = "-- "
|
||||
return first .. prefix .. str:gsub("\n", "\n" .. prefix)
|
||||
end
|
||||
|
||||
---@param param LuaParam
|
||||
function M.type(param)
|
||||
local type = param.type and param.type ~= "" and param.type or "any"
|
||||
|
||||
if type == "any" then
|
||||
for t, names in pairs(M.name2type) do
|
||||
if vim.tbl_contains(names, param.name) then
|
||||
return t
|
||||
end
|
||||
end
|
||||
end
|
||||
for t, names in pairs(M.name2type) do
|
||||
if vim.tbl_contains(names, type) then
|
||||
return t
|
||||
end
|
||||
end
|
||||
|
||||
if M.nvim_types[type] then
|
||||
return type
|
||||
end
|
||||
|
||||
if M.lua_types[type] then
|
||||
return M.lua_types[type]
|
||||
end
|
||||
|
||||
if type == "arrayof(string)" then
|
||||
type = "string[]"
|
||||
elseif type == "arrayof(integer, 2)" then
|
||||
type = "number[]"
|
||||
elseif type == "dictionaryof(luaref)" then
|
||||
type = "table<string, luaref>"
|
||||
elseif type:find("^arrayof%(") then
|
||||
return "any[]"
|
||||
elseif type:find("^dict%(") or type:find("^dictionaryof%(") then
|
||||
return "table<string, any>"
|
||||
end
|
||||
return type
|
||||
end
|
||||
|
||||
---@param param LuaParam
|
||||
function M.param(param)
|
||||
local parts = {}
|
||||
if param.name then
|
||||
if M.is_keyword(param.name) then
|
||||
param.name = param.name .. "_"
|
||||
end
|
||||
table.insert(parts, param.name .. (param.optional and "?" or ""))
|
||||
end
|
||||
|
||||
local type = M.type(param)
|
||||
if type == "nil" then
|
||||
return ""
|
||||
end
|
||||
|
||||
if type then
|
||||
table.insert(parts, type)
|
||||
end
|
||||
|
||||
if param.doc then
|
||||
table.insert(parts, "# " .. param.doc)
|
||||
end
|
||||
|
||||
if not param.doc and type == "any" and not param.optional then
|
||||
return ""
|
||||
end
|
||||
|
||||
local ret = table.concat(parts, " ")
|
||||
if not param.name then
|
||||
return M.comment("@return " .. ret, "-") .. "\n"
|
||||
else
|
||||
return M.comment("@param " .. ret, "-") .. "\n"
|
||||
end
|
||||
end
|
||||
|
||||
function M.fqn(name)
|
||||
local real_fn = vim.tbl_get(_G, unpack(vim.split(name, ".", { plain = true })))
|
||||
if vim.api[name] then
|
||||
return "vim.api." .. name
|
||||
elseif vim[name] then
|
||||
return "vim." .. name
|
||||
elseif name:find("^[a-zA-Z_]+$") and vim.fn.exists("*" .. name) == 1 then
|
||||
return "vim.fn." .. name
|
||||
elseif name:find("^vim") and real_fn then
|
||||
return name
|
||||
end
|
||||
-- if we get here, it means the function is RPC only, or no longer exists
|
||||
end
|
||||
|
||||
function M.is_lua(name)
|
||||
local real_fn = vim.tbl_get(_G, unpack(vim.split(name, ".", { plain = true })))
|
||||
|
||||
-- some plugins (like Noice) wrap api functions. This deals with that
|
||||
if real_fn and name:find("vim%.api%.") then
|
||||
return false
|
||||
elseif type(real_fn) == "function" then
|
||||
local info = debug.getinfo(real_fn, "S")
|
||||
return info.what == "Lua"
|
||||
elseif type(real_fn) == "table" then
|
||||
return true
|
||||
elseif not real_fn then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--- @param fun LuaFunction
|
||||
function M.fun(fun)
|
||||
local ret = ""
|
||||
if fun.doc ~= "" then
|
||||
-- make markdown lua code blocks for code regions
|
||||
local ft = fun.name:find("vim.fn") and "vim" or "lua"
|
||||
local lines = vim.split(fun.doc, "\n")
|
||||
|
||||
local l = 1
|
||||
while l < #lines do
|
||||
local line = lines[l]
|
||||
local from, to, before, lang = line:find("^(%s*.*)>([a-z]*)%s*$")
|
||||
if from then
|
||||
before = (not before:find("^%s*$")) and before or nil
|
||||
lang = lang ~= "" and lang or nil
|
||||
for i = l + 1, #lines do
|
||||
if lines[i]:find("^%S") or lines[i]:find("^%s*<") or i == #lines then
|
||||
lines[l] = (before and (before .. "\n") or "") .. "```" .. (lang or ft)
|
||||
if lines[i]:find("^%s*<%s*$") then
|
||||
lines[i] = "```"
|
||||
elseif lines[i]:find("^%s*<") then
|
||||
lines[i] = "```\n" .. lines[i]:gsub("<", "")
|
||||
else
|
||||
lines[i] = lines[i] .. "\n```"
|
||||
end
|
||||
l = i
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
l = l + 1
|
||||
end
|
||||
local doc = table.concat(lines, "\n")
|
||||
doc = M.fix_indent(doc)
|
||||
ret = ret .. (M.comment(doc)) .. "\n"
|
||||
end
|
||||
|
||||
if fun.seealso and #fun.seealso > 0 then
|
||||
for _, also in ipairs(fun.seealso) do
|
||||
ret = ret .. "--- @see " .. also .. "\n"
|
||||
end
|
||||
end
|
||||
|
||||
local params = {}
|
||||
|
||||
for _, param in pairs(fun.params) do
|
||||
ret = ret .. M.param(param)
|
||||
table.insert(params, param.name)
|
||||
end
|
||||
for _, r in pairs(fun["return"]) do
|
||||
ret = ret .. M.param(r)
|
||||
end
|
||||
|
||||
local signature = "function %s(%s) end"
|
||||
|
||||
-- handle special Lua names. Set as a field instead of a function
|
||||
if M.is_keyword(fun.name:match("[^.]+$")) then
|
||||
local prefix, name = fun.name:match("(.*)%.([^.]+)$")
|
||||
fun.name = name
|
||||
signature = prefix .. "[%q] = function(%s) end"
|
||||
end
|
||||
|
||||
if fun.overload then
|
||||
for _, overload in ipairs(fun.overload) do
|
||||
ret = ret .. "--- @overload " .. overload .. "\n"
|
||||
end
|
||||
end
|
||||
|
||||
ret = ret .. signature:format(fun.name, table.concat(params, ", "))
|
||||
return ret .. "\n\n"
|
||||
end
|
||||
|
||||
---@param text string
|
||||
function M.fix_indent(text)
|
||||
local lines = vim.split(text, "\n")
|
||||
local indent = 10
|
||||
for l, line in ipairs(lines) do
|
||||
if not (line:find("^%s*$") or line:find("^```")) then
|
||||
line = line:gsub(" ", "\t")
|
||||
lines[l] = line
|
||||
local prefix = line:match("^\t+")
|
||||
if prefix then
|
||||
indent = math.min(indent, #prefix)
|
||||
end
|
||||
end
|
||||
end
|
||||
if indent > 0 then
|
||||
for l, line in ipairs(lines) do
|
||||
lines[l] = line:gsub("^" .. ("\t"):rep(indent), ""):gsub("\t", " ")
|
||||
end
|
||||
end
|
||||
return table.concat(lines, "\n")
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,80 @@
|
||||
local Annotations = require("neodev.build.annotations")
|
||||
local Docs = require("neodev.build.docs")
|
||||
|
||||
---@class NvimApiInfo
|
||||
---@field functions NvimApiFunction[]
|
||||
|
||||
---@class NvimApiFunction
|
||||
---@field name string
|
||||
---@field deprecated_since? number
|
||||
---@field parameters {[1]: string, [2]:string}[]
|
||||
---@field return_type string
|
||||
---@field since number
|
||||
---@field method? boolean
|
||||
|
||||
---@class LuaApiFunction: LuaFunction
|
||||
---@field params_index? table<string, LuaParam>
|
||||
---@field info? NvimApiFunction
|
||||
|
||||
local M = {}
|
||||
|
||||
---@return table<string, LuaFunction>
|
||||
function M.get()
|
||||
local functions = Docs.parse_functions("api", {
|
||||
name = Annotations.fqn,
|
||||
})
|
||||
---@cast functions table<string, LuaApiFunction>
|
||||
|
||||
-- add params index
|
||||
for _, fun in pairs(functions) do
|
||||
fun.params_index = {}
|
||||
for _, param in ipairs(fun.params) do
|
||||
local name = param.name
|
||||
if name then
|
||||
fun.params_index[name] = param
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@type NvimApiInfo
|
||||
local info = vim.fn.api_info()
|
||||
|
||||
-- add api info
|
||||
for _, fun in ipairs(info.functions) do
|
||||
if not fun.deprecated_since then
|
||||
local name = Annotations.fqn(fun.name)
|
||||
if name then
|
||||
if not functions[name] then
|
||||
functions[name] = {
|
||||
doc = "",
|
||||
name = name,
|
||||
params = {},
|
||||
params_index = {},
|
||||
}
|
||||
end
|
||||
functions[name].info = fun
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- merge api info
|
||||
for _, fun in pairs(functions) do
|
||||
if fun.info then
|
||||
for _, param in ipairs(fun.info.parameters) do
|
||||
if fun.params_index[param[2]] then
|
||||
fun.params_index[param[2]].type = param[1]:lower()
|
||||
else
|
||||
fun.params_index[param[2]] = { name = param[2], type = param[1]:lower() }
|
||||
end
|
||||
end
|
||||
local return_type = fun.info.return_type:lower()
|
||||
fun["return"] = { { type = return_type == "nil" and nil or return_type } }
|
||||
end
|
||||
end
|
||||
|
||||
return functions
|
||||
end
|
||||
|
||||
M.get()
|
||||
|
||||
return M
|
||||
@ -0,0 +1,340 @@
|
||||
local Util = require("neodev.util")
|
||||
local Annotations = require("neodev.build.annotations")
|
||||
|
||||
local M = {}
|
||||
|
||||
M.function_pattern = "^(%S-%([^(]-%))"
|
||||
M.function_signature_pattern = "^(%S-)%(([^(]-)%)"
|
||||
M.vim_type_map = {
|
||||
number = "number",
|
||||
float = "float",
|
||||
string = "string",
|
||||
list = "any[]",
|
||||
any = "any",
|
||||
funcref = "fun()",
|
||||
dict = "table<string, any>",
|
||||
none = "nil",
|
||||
set = "boolean",
|
||||
boolean = "boolean",
|
||||
}
|
||||
|
||||
---@param name string
|
||||
function M.read(name)
|
||||
local docs = vim.fn.expand("$VIMRUNTIME/doc")
|
||||
local txtfile = docs .. "/" .. name .. ".txt"
|
||||
|
||||
---@type string[]
|
||||
local lines = {}
|
||||
for line in io.lines(txtfile) do
|
||||
table.insert(lines, line)
|
||||
end
|
||||
return lines
|
||||
end
|
||||
|
||||
---@return string, string[]
|
||||
function M.strip_tags(str)
|
||||
local tags = {}
|
||||
return str
|
||||
:gsub(
|
||||
"(%*%S-%*)",
|
||||
---@param tag string
|
||||
function(tag)
|
||||
tag = tag:sub(2, -2)
|
||||
table.insert(tags, tag)
|
||||
return ""
|
||||
end
|
||||
)
|
||||
:gsub("%s*$", ""),
|
||||
tags
|
||||
end
|
||||
|
||||
---@param text string
|
||||
function M.trim(text)
|
||||
return text:gsub("^%s*\n", ""):gsub("\n+$", "")
|
||||
end
|
||||
|
||||
---@param name string
|
||||
---@param opts { pattern: string, continuation?: string, context?: number}
|
||||
function M.parse(name, opts)
|
||||
opts = opts or {}
|
||||
opts.continuation = opts.continuation or "^[%s<>]"
|
||||
opts.context = opts.context or 1
|
||||
|
||||
local tags = {}
|
||||
local line_tags = {}
|
||||
local chunk_tags = {}
|
||||
local chunk_match = {}
|
||||
local chunk = {}
|
||||
---@type {tags:string[], text:string, match: string[]}[]
|
||||
local ret = {}
|
||||
|
||||
local function save()
|
||||
if #chunk > 0 then
|
||||
table.insert(ret, {
|
||||
tags = vim.deepcopy(chunk_tags),
|
||||
text = M.trim(table.concat(chunk, "\n")),
|
||||
match = vim.deepcopy(chunk_match),
|
||||
})
|
||||
end
|
||||
chunk = {}
|
||||
chunk_tags = {}
|
||||
end
|
||||
local lines = M.read(name)
|
||||
for l, line in ipairs(lines) do
|
||||
line, line_tags = M.strip_tags(line)
|
||||
|
||||
if #line_tags > 0 then
|
||||
tags = line_tags
|
||||
end
|
||||
|
||||
local context = line
|
||||
for c = 1, opts.context do
|
||||
if lines[l + c] then
|
||||
context = context .. "\n" .. lines[l + c]
|
||||
end
|
||||
end
|
||||
|
||||
local match = { context:match(opts.pattern) }
|
||||
|
||||
if #match > 0 then
|
||||
save()
|
||||
chunk_match = match
|
||||
chunk_tags = vim.deepcopy(tags)
|
||||
table.insert(chunk, line)
|
||||
elseif #chunk > 0 and (line:find(opts.continuation) or line:find("^%s*$")) then
|
||||
table.insert(chunk, line)
|
||||
else
|
||||
save()
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
---@return {name: string, params: {name:string, optional?:boolean}[], doc: string}?
|
||||
---@return LuaFunction?
|
||||
function M.parse_signature(line)
|
||||
---@type string, string, string
|
||||
local name, sig, doc = line:match(M.function_signature_pattern .. "(.*)")
|
||||
if name then
|
||||
-- Parse args
|
||||
local optional_from = sig:find("%[")
|
||||
sig = sig:gsub("%[", "")
|
||||
sig = sig:gsub("%]", "")
|
||||
sig = sig:gsub("\n", " ")
|
||||
sig = sig:gsub("\t", " ")
|
||||
local params = {}
|
||||
---@type table<string,boolean>
|
||||
local index = {}
|
||||
local from = 0
|
||||
local to = 0
|
||||
local param = ""
|
||||
while from do
|
||||
---@type number, number, string
|
||||
from, to, param = sig:find("{?([^ ,{}]+)}?", to + 1)
|
||||
if from then
|
||||
local optional = optional_from and from >= optional_from and true or nil
|
||||
if param:sub(1, 1) == "*" then
|
||||
optional = true
|
||||
param = param:sub(2)
|
||||
end
|
||||
param = param:gsub("%-", "_")
|
||||
if param:find("^%d+$") then
|
||||
param = "p" .. param
|
||||
end
|
||||
|
||||
-- check for duplicate params
|
||||
local p = param
|
||||
local c = 1
|
||||
while index[param] do
|
||||
param = p .. c
|
||||
c = c + 1
|
||||
end
|
||||
index[param] = true
|
||||
|
||||
table.insert(params, {
|
||||
name = param,
|
||||
optional = optional,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
return { name = name, params = params, doc = M.trim(doc) }
|
||||
end
|
||||
end
|
||||
|
||||
function M.options()
|
||||
---@type table<string, string>
|
||||
local ret = {}
|
||||
|
||||
local option_pattern = "^'(%S-)'%s*"
|
||||
|
||||
local options = M.parse("options", { pattern = option_pattern })
|
||||
|
||||
for _, option in ipairs(options) do
|
||||
local name = option.match[1]
|
||||
local doc = option.text:gsub("'(%S-)'", "`'%1'` ")
|
||||
ret[name] = doc
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
---@param doc string
|
||||
---@param opts? {filter?: (fun(name:string):boolean), name?: (fun(name:string):string)}
|
||||
function M.parse_functions(doc, opts)
|
||||
opts = opts or {}
|
||||
---@type table<string, LuaFunction>
|
||||
local ret = {}
|
||||
|
||||
local functions = M.parse(doc, { pattern = M.function_pattern, context = 2 })
|
||||
|
||||
for _, fun in ipairs(functions) do
|
||||
local text = fun.text
|
||||
-- replace function name by the function tag, to make sure it is fully qualified
|
||||
for _, tag in ipairs(fun.tags) do
|
||||
if tag:find("vim.*%(%)$") then
|
||||
tag = tag:sub(1, -3)
|
||||
local name = text:match(M.function_signature_pattern)
|
||||
if tag:sub(-#name) == name then
|
||||
text = text:gsub("^%S-%(", tag .. "(")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local parse = M.parse_signature(text)
|
||||
|
||||
if parse then
|
||||
local name = parse.name
|
||||
|
||||
if opts.name then
|
||||
name = opts.name(name)
|
||||
end
|
||||
|
||||
if name and (opts.filter == nil or opts.filter(name)) then
|
||||
ret[name] = {
|
||||
name = name,
|
||||
params = parse.params,
|
||||
doc = parse.doc,
|
||||
["return"] = {},
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
function M.lua()
|
||||
return M.parse_functions("lua", {
|
||||
filter = function(name)
|
||||
return not Annotations.is_lua(name)
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
function M.luv()
|
||||
local ret = M.parse_functions("luvref", {
|
||||
filter = function(name)
|
||||
return not Annotations.is_lua(name)
|
||||
end,
|
||||
name = function(name)
|
||||
local ret = name:gsub("^uv%.", "vim.loop.")
|
||||
return ret
|
||||
end,
|
||||
})
|
||||
Util.for_each(ret, function(_, fun)
|
||||
local returns = fun.doc:match("%s*Returns: (.*)\n")
|
||||
if not returns then
|
||||
returns = fun.doc:match("%s*Returns %(sync version%): (.*)\n")
|
||||
end
|
||||
---@type LuaParam
|
||||
local retval = {}
|
||||
if returns then
|
||||
---@diagnostic disable-next-line: no-unknown
|
||||
for t in returns:gmatch("`(.-)`") do
|
||||
if t == "nil" or t == "fail" then
|
||||
retval.optional = true
|
||||
elseif not retval.type then
|
||||
retval.type = t:find("userdata") and "userdata" or t
|
||||
end
|
||||
end
|
||||
end
|
||||
if not vim.tbl_isempty(retval) then
|
||||
fun["return"] = { retval }
|
||||
end
|
||||
end)
|
||||
return ret
|
||||
end
|
||||
|
||||
function M.commands()
|
||||
local pattern = "|:%S-|%s+:([a-z]%S-)%s+(.*)"
|
||||
local builtins = M.parse("index", { pattern = pattern, context = 0, continuation = "^%s+" })
|
||||
---@type table<string,string>
|
||||
local ret = {}
|
||||
for _, builtin in ipairs(builtins) do
|
||||
if vim.tbl_contains(builtin.tags, "ex-cmd-index") then
|
||||
local cmd = builtin.match[1]
|
||||
local desc = builtin.match[2]
|
||||
local i = cmd:find("%[")
|
||||
if i then
|
||||
ret[cmd:sub(1, i - 1)] = desc
|
||||
cmd = cmd:gsub("[%[%]]", "")
|
||||
end
|
||||
ret[cmd] = desc
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
function M.functions()
|
||||
local builtins = M.parse("builtin", { pattern = M.function_pattern, context = 2 })
|
||||
|
||||
---@type table<string, string>
|
||||
local retvals = {}
|
||||
|
||||
-- Parse return values from `:h builtin-function-list`
|
||||
for _, builtin in ipairs(builtins) do
|
||||
if vim.tbl_contains(builtin.tags, "builtin-function-list") then
|
||||
local text = builtin.text
|
||||
-- replace any whitespace after the function by a tab character
|
||||
text = text:gsub(M.function_pattern .. "%s+", "%1\t")
|
||||
-- replace consecutive whitespace by tabs
|
||||
text = text:gsub("%s%s+", "\t")
|
||||
---@type string, string, string
|
||||
local name, _args, retval = text:match(M.function_signature_pattern .. "\t(%w+)")
|
||||
if name then
|
||||
retval = retval:lower()
|
||||
if M.vim_type_map[retval] then
|
||||
retval = M.vim_type_map[retval]
|
||||
if retval ~= "nil" then
|
||||
retvals["vim.fn." .. name] = retval
|
||||
end
|
||||
else
|
||||
Util.debug("Unknown retval: " .. retval)
|
||||
end
|
||||
else
|
||||
Util.error("Couldnt parse builtin-function-list: " .. vim.inspect(builtin))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local ret = M.parse_functions("builtin", {
|
||||
filter = function(name)
|
||||
name = name:match("vim%.fn%.(.*)")
|
||||
if name:find("%.") then
|
||||
return false
|
||||
end
|
||||
return name and (vim.fn.exists("*" .. name) == 1)
|
||||
end,
|
||||
name = function(name)
|
||||
return "vim.fn." .. name
|
||||
end,
|
||||
})
|
||||
for k, fun in pairs(ret) do
|
||||
if retvals[k] then
|
||||
fun["return"] = { { type = retvals[k]:lower() } }
|
||||
end
|
||||
end
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,126 @@
|
||||
local Config = require("neodev.config")
|
||||
local Util = require("neodev.util")
|
||||
|
||||
local Annotations = require("neodev.build.annotations")
|
||||
local Api = require("neodev.build.api")
|
||||
local Docs = require("neodev.build.docs")
|
||||
local Mpack = require("neodev.build.mpack")
|
||||
local Writer = require("neodev.build.writer")
|
||||
local Options = require("neodev.build.options")
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.api()
|
||||
local api = Api.get()
|
||||
|
||||
-- Only load mpack on nightly and add any missing functions
|
||||
-- Typically hidden functions
|
||||
if Config.version() == "nightly" then
|
||||
local functions = Mpack.read("api.mpack")
|
||||
|
||||
for k, v in pairs(functions) do
|
||||
if not api[k] then
|
||||
api[k] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
M.write("api", api)
|
||||
end
|
||||
|
||||
---@return table<string, LuaFunction>, string?
|
||||
function M.override(fname)
|
||||
local override = Config.root("/types/override/" .. fname .. ".lua")
|
||||
if override then
|
||||
local code = Util.read_file(override)
|
||||
local mod = {}
|
||||
local mod_code = code:match("\n(return.*)") or code:match("^(return.*)")
|
||||
if mod_code then
|
||||
mod = load(mod_code)()
|
||||
end
|
||||
code = code:gsub("\nreturn.*", "")
|
||||
code = code:gsub("^return.*", "")
|
||||
return mod, code
|
||||
end
|
||||
return {}
|
||||
end
|
||||
|
||||
---@param fname string
|
||||
---@param functions table<string, LuaFunction>
|
||||
function M.write(fname, functions)
|
||||
local override, override_code = M.override(fname)
|
||||
functions = vim.tbl_deep_extend("force", functions, override)
|
||||
|
||||
local writer = Writer(fname)
|
||||
if override_code then
|
||||
writer:write(override_code .. "\n\n")
|
||||
end
|
||||
Util.for_each(functions, function(_, fun)
|
||||
writer:write(Annotations.fun(fun))
|
||||
end)
|
||||
|
||||
writer:close()
|
||||
end
|
||||
|
||||
function M.alias()
|
||||
local writer = Writer("alias")
|
||||
Util.for_each(Annotations.nvim_types, function(key, value)
|
||||
writer:write(("---@alias %s %s"):format(key, value) .. "\n")
|
||||
end)
|
||||
writer:close()
|
||||
end
|
||||
|
||||
function M.commands()
|
||||
local writer = Writer("cmd")
|
||||
Util.for_each(Docs.commands(), function(cmd, desc)
|
||||
writer:write(Annotations.comment(desc) .. "\n")
|
||||
if Annotations.is_keyword(cmd) then
|
||||
writer:write(("vim.cmd[%q] = function(...)end"):format(cmd) .. "\n\n")
|
||||
else
|
||||
writer:write(("function vim.cmd.%s(...)end"):format(cmd) .. "\n\n")
|
||||
end
|
||||
end)
|
||||
writer:close()
|
||||
end
|
||||
|
||||
function M.clean()
|
||||
local types = Config.types()
|
||||
for _, f in pairs(vim.fn.expand(types .. "/*.lua", false, true)) do
|
||||
if not f:find("/vim.lua", 1, true) then
|
||||
vim.loop.fs_unlink(f)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M.uv()
|
||||
local writer = Writer("uv")
|
||||
writer:write(Util.fetch("https://raw.githubusercontent.com/Bilal2453/luvit-meta/main/library/uv.lua"))
|
||||
end
|
||||
|
||||
function M.lpeg()
|
||||
local writer = Writer("lpeg")
|
||||
writer:write(Util.fetch("https://raw.githubusercontent.com/LuaCATS/lpeg/main/library/lpeg.lua"))
|
||||
end
|
||||
|
||||
function M.build()
|
||||
M.clean()
|
||||
M.uv()
|
||||
M.alias()
|
||||
M.commands()
|
||||
|
||||
if vim.fn.has("nvim-0.10") == 0 then
|
||||
M.lpeg()
|
||||
|
||||
Options.build()
|
||||
|
||||
M.api()
|
||||
|
||||
-- M.write("luv", Docs.luv())
|
||||
M.write("lua", Docs.lua())
|
||||
M.write("vim.fn", Docs.functions())
|
||||
end
|
||||
end
|
||||
|
||||
M.build()
|
||||
|
||||
return M
|
||||
@ -0,0 +1,73 @@
|
||||
local Annotations = require("neodev.build.annotations")
|
||||
local util = require("neodev.util")
|
||||
local M = {}
|
||||
|
||||
---@class MpackFunction
|
||||
---@field doc string[]
|
||||
---@field parameters {[1]: string, [2]:string}[]
|
||||
---@field parameters_doc table<string, string>
|
||||
---@field return string[]
|
||||
---@field seealso string[]
|
||||
---@field signature string
|
||||
|
||||
function M.read(mpack)
|
||||
mpack = "data/" .. mpack
|
||||
---@type table<string, MpackFunction>
|
||||
local data = vim.mpack.decode(util.read_file(mpack))
|
||||
|
||||
---@type table<string, LuaFunction>
|
||||
local ret = {}
|
||||
for name, fun in pairs(data) do
|
||||
name = Annotations.fqn(name)
|
||||
if name then
|
||||
ret[name] = M.process(name, fun)
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
---@param name string
|
||||
--- @param fun MpackFunction
|
||||
--- @return LuaFunction
|
||||
function M.process(name, fun)
|
||||
---@type LuaFunction
|
||||
local ret = {
|
||||
doc = (fun.doc and fun.doc[1]) and table.concat(fun.doc, "\n\n") or "",
|
||||
name = name,
|
||||
params = {},
|
||||
seealso = fun.seealso or {},
|
||||
["return"] = {},
|
||||
}
|
||||
|
||||
for _, r in pairs(fun["return"]) do
|
||||
table.insert(ret["return"], { doc = r })
|
||||
end
|
||||
|
||||
for i, p in ipairs(fun.parameters or {}) do
|
||||
local type = p[1]
|
||||
local pname = p[2]
|
||||
local param = { name = pname }
|
||||
if type ~= "" then
|
||||
param.type = type:lower()
|
||||
end
|
||||
param.doc = fun.parameters_doc and fun.parameters_doc[pname] or nil
|
||||
|
||||
if param.type and param.type:find("%*$") then
|
||||
param.type = param.type:sub(1, -2)
|
||||
param.optional = true
|
||||
end
|
||||
-- only include err param if it's documented
|
||||
-- most nvim_ functions have an err param at the end, but these should not be included
|
||||
local skip = i == #fun.parameters and (pname == "err" or pname == "error")
|
||||
-- skip self params
|
||||
if param.name == "self" or param.name == "" or param.name == "arena" then
|
||||
skip = true
|
||||
end
|
||||
if not skip then
|
||||
table.insert(ret.params, param)
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,106 @@
|
||||
local Docs = require("neodev.build.docs")
|
||||
local Writer = require("neodev.build.writer")
|
||||
local Annotations = require("neodev.build.annotations")
|
||||
local Util = require("neodev.util")
|
||||
local Config = require("neodev.config")
|
||||
|
||||
---@class OptionInfo
|
||||
---@field allows_duplicates boolean
|
||||
---@field commalist boolean
|
||||
---@field default any
|
||||
---@field flaglist boolean
|
||||
---@field global_local boolean
|
||||
---@field name string
|
||||
---@field scope "global" | "win" | "buf"
|
||||
---@field shortname string
|
||||
---@field type string
|
||||
|
||||
---@alias OptionsInfo table<string, OptionInfo>
|
||||
|
||||
local M = {}
|
||||
|
||||
M.metatype2lua = {
|
||||
map = function(info)
|
||||
return ("table<string, %s>"):format(info.type)
|
||||
end,
|
||||
set = function(info)
|
||||
return ("%s[]"):format(info.type)
|
||||
end,
|
||||
array = function(info)
|
||||
return ("%s[]"):format(info.type)
|
||||
end,
|
||||
}
|
||||
|
||||
function M.build()
|
||||
local writer = Writer("options")
|
||||
|
||||
local docs = Docs.options()
|
||||
|
||||
---@type OptionsInfo
|
||||
local info = vim.api.nvim_get_all_options_info()
|
||||
|
||||
---@param scope string
|
||||
local function write(scope)
|
||||
local var = "vim." .. scope:sub(1, 1) .. "o"
|
||||
|
||||
writer:write("---@class " .. var .. "\n")
|
||||
writer:write(var .. " = {}\n\n")
|
||||
Util.for_each(info, function(name, option)
|
||||
if option.scope == scope then
|
||||
local default = vim.inspect(option.default)
|
||||
local str = ""
|
||||
if docs[name] then
|
||||
str = str .. Annotations.comment(docs[name]) .. "\n"
|
||||
end
|
||||
str = str .. ("%s.%s = %s\n"):format(var, name, default)
|
||||
if option.shortname ~= "" then
|
||||
str = str .. ("%s.%s = %s.%s\n"):format(var, option.shortname, var, name)
|
||||
end
|
||||
writer:write(str)
|
||||
end
|
||||
end)
|
||||
writer:write("\n\n")
|
||||
end
|
||||
|
||||
write("global")
|
||||
write("win")
|
||||
write("buf")
|
||||
|
||||
-- Write vim.opt
|
||||
Util.for_each(info, function(name, option)
|
||||
local str = ""
|
||||
if docs[name] then
|
||||
str = str .. Annotations.comment(docs[name]) .. "\n"
|
||||
end
|
||||
---@type string
|
||||
local return_type = option.type
|
||||
|
||||
pcall(function()
|
||||
---@diagnostic disable-next-line: no-unknown
|
||||
return_type = vim.opt[name]._info.metatype
|
||||
if M.metatype2lua[return_type] then
|
||||
---@diagnostic disable-next-line: no-unknown
|
||||
return_type = M.metatype2lua[return_type](option)
|
||||
end
|
||||
end)
|
||||
|
||||
str = str .. ("--- @class vim.opt.%s: vim.Option,%s\n"):format(name, return_type)
|
||||
str = str .. ("--- @operator add: vim.opt.%s\n"):format(name)
|
||||
str = str .. ("--- @operator sub: vim.opt.%s\n"):format(name)
|
||||
str = str .. ("--- @operator pow: vim.opt.%s\n"):format(name)
|
||||
str = str .. ("vim.opt.%s = %s\n"):format(name, vim.inspect(option.default))
|
||||
if option.shortname ~= "" then
|
||||
str = str .. ("vim.opt.%s = vim.opt.%s\n"):format(option.shortname, name)
|
||||
end
|
||||
|
||||
str = str .. ("--- @return %s\nfunction vim.opt.%s:get()end\n\n"):format(return_type, name)
|
||||
writer:write(str)
|
||||
end)
|
||||
|
||||
local code = Util.read_file(Config.root("/types/override/options.lua"))
|
||||
writer:write(code .. "\n")
|
||||
|
||||
writer:close()
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,53 @@
|
||||
local config = require("neodev.config")
|
||||
|
||||
---@class AnnotationWriter
|
||||
---@field name string
|
||||
---@field fd? number
|
||||
---@field fnum number
|
||||
---@field size number
|
||||
local M = {}
|
||||
M.__index = M
|
||||
|
||||
M.MAX_SIZE = 1024 * 200
|
||||
|
||||
---@return AnnotationWriter
|
||||
function M.new(name)
|
||||
local self = setmetatable({}, M)
|
||||
self.name = name
|
||||
self.size = 0
|
||||
self.fnum = 0
|
||||
return self
|
||||
end
|
||||
|
||||
function M:close()
|
||||
if self.fd then
|
||||
vim.loop.fs_close(self.fd)
|
||||
end
|
||||
end
|
||||
|
||||
function M:check()
|
||||
if not self.fd or self.size > M.MAX_SIZE then
|
||||
self:close()
|
||||
local types = config.types()
|
||||
local fname = types .. "/" .. self.name
|
||||
if self.fnum > 0 then
|
||||
fname = fname .. "." .. self.fnum
|
||||
end
|
||||
self.fd = vim.loop.fs_open(fname .. ".lua", "w+", 420)
|
||||
self.fnum = self.fnum + 1
|
||||
self.size = 0
|
||||
self:intro()
|
||||
end
|
||||
end
|
||||
|
||||
function M:intro()
|
||||
self:write("---@meta\n\n")
|
||||
end
|
||||
|
||||
function M:write(text)
|
||||
self:check()
|
||||
vim.loop.fs_write(self.fd, text, -1)
|
||||
self.size = self.size + #text
|
||||
end
|
||||
|
||||
return M.new
|
||||
@ -0,0 +1,57 @@
|
||||
local M = {}
|
||||
|
||||
--- @class LuaDevOptions
|
||||
M.defaults = {
|
||||
library = {
|
||||
enabled = true, -- when not enabled, neodev will not change any settings to the LSP server
|
||||
-- these settings will be used for your neovim config directory
|
||||
runtime = true, -- runtime path
|
||||
types = true, -- full signature, docs and completion of vim.api, vim.treesitter, vim.lsp and others
|
||||
---@type boolean|string[]
|
||||
plugins = true, -- installed opt or start plugins in packpath
|
||||
-- you can also specify the list of plugins to make available as a workspace library
|
||||
-- plugins = { "nvim-treesitter", "plenary.nvim", "telescope.nvim" },
|
||||
},
|
||||
setup_jsonls = true, -- configures jsonls to provide completion for .luarc.json files
|
||||
-- for your neovim config directory, the config.library settings will be used as is
|
||||
-- for plugin directories (root_dirs having a /lua directory), config.library.plugins will be disabled
|
||||
-- for any other directory, config.library.enabled will be set to false
|
||||
override = function(root_dir, options) end,
|
||||
-- With lspconfig, Neodev will automatically setup your lua-language-server
|
||||
-- If you disable this, then you have to set {before_init=require("neodev.lsp").before_init}
|
||||
-- in your lsp start options
|
||||
lspconfig = true,
|
||||
-- much faster, but needs a recent built of lua-language-server
|
||||
-- needs lua-language-server >= 3.6.0
|
||||
pathStrict = true,
|
||||
debug = false,
|
||||
}
|
||||
|
||||
--- @type LuaDevOptions
|
||||
M.options = {}
|
||||
|
||||
function M.setup(options)
|
||||
M.options = vim.tbl_deep_extend("force", {}, M.defaults, options or {})
|
||||
end
|
||||
|
||||
function M.types()
|
||||
return M.root("/types/" .. M.version())
|
||||
end
|
||||
|
||||
---@param root? string
|
||||
function M.root(root)
|
||||
local f = debug.getinfo(1, "S").source:sub(2)
|
||||
return vim.loop.fs_realpath(vim.fn.fnamemodify(f, ":h:h:h") .. "/" .. (root or ""))
|
||||
end
|
||||
|
||||
---@return "nightly" | "stable"
|
||||
function M.version()
|
||||
return vim.version().prerelease and "nightly" or "stable"
|
||||
end
|
||||
|
||||
---@return LuaDevOptions
|
||||
function M.merge(options)
|
||||
return vim.tbl_deep_extend("force", {}, M.options, options or {})
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,39 @@
|
||||
local M = {}
|
||||
|
||||
local function neoconf(config)
|
||||
pcall(function()
|
||||
require("neoconf.plugins").register({
|
||||
on_schema = function(schema)
|
||||
schema:import("neodev", config.defaults)
|
||||
schema:set("neodev.library.plugins", {
|
||||
description = "true/false or an array of plugin names to enable",
|
||||
anyOf = {
|
||||
{ type = "boolean" },
|
||||
{ type = "array", items = { type = "string" } },
|
||||
},
|
||||
})
|
||||
end,
|
||||
})
|
||||
end)
|
||||
end
|
||||
|
||||
---@param opts? LuaDevOptions
|
||||
function M.setup(opts)
|
||||
local config = require("neodev.config")
|
||||
config.setup(opts)
|
||||
|
||||
if config.options.lspconfig then
|
||||
require("neodev.lsp").setup()
|
||||
end
|
||||
|
||||
neoconf(config)
|
||||
|
||||
-- leave this for now for backward compatibility
|
||||
return {
|
||||
settings = {
|
||||
legacy = true,
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
return M
|
||||
115
config/neovim/store/lazy-plugins/neodev.nvim/lua/neodev/lsp.lua
Normal file
115
config/neovim/store/lazy-plugins/neodev.nvim/lua/neodev/lsp.lua
Normal file
@ -0,0 +1,115 @@
|
||||
local util = require("neodev.util")
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.setup()
|
||||
local opts = require("neodev.config").options
|
||||
|
||||
local lsputil = require("lspconfig.util")
|
||||
local hook = lsputil.add_hook_after
|
||||
lsputil.on_setup = hook(lsputil.on_setup, function(config)
|
||||
if opts.setup_jsonls and config.name == "jsonls" then
|
||||
M.setup_jsonls(config)
|
||||
end
|
||||
if config.name == "lua_ls" then
|
||||
config.on_new_config = hook(config.on_new_config, M.on_new_config)
|
||||
-- config.before_init = hook(config.before_init, M.before_init)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function M.setup_jsonls(config)
|
||||
local schemas = config.settings.json and config.settings.json.schemas or {}
|
||||
table.insert(schemas, {
|
||||
name = "LuaLS Settings",
|
||||
url = "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json",
|
||||
fileMatch = { ".luarc.json", ".luarc.jsonc" },
|
||||
})
|
||||
config.settings = vim.tbl_deep_extend("force", config.settings, {
|
||||
json = {
|
||||
schemas = schemas,
|
||||
validate = {
|
||||
enable = true,
|
||||
},
|
||||
},
|
||||
})
|
||||
end
|
||||
|
||||
function M.before_init(params, config)
|
||||
M.on_new_config(config, params.rootPath)
|
||||
end
|
||||
|
||||
function M.on_new_config(config, root_dir)
|
||||
-- don't do anything when old style setup was used
|
||||
if config.settings.legacy then
|
||||
util.warn(
|
||||
"You're using the old way of setting up neodev (previously lua-dev).\nPlease check the docs at https://github.com/folke/neodev.nvim#-setup"
|
||||
)
|
||||
return
|
||||
end
|
||||
|
||||
local lua_root = util.find_root()
|
||||
|
||||
local opts = require("neodev.config").merge()
|
||||
|
||||
opts.library.enabled = util.is_nvim_config()
|
||||
|
||||
if not opts.library.enabled and lua_root then
|
||||
opts.library.enabled = true
|
||||
opts.library.plugins = false
|
||||
end
|
||||
|
||||
pcall(function()
|
||||
opts = require("neoconf").get("neodev", opts, { file = root_dir })
|
||||
end)
|
||||
|
||||
pcall(opts.override, root_dir, opts.library)
|
||||
|
||||
local library = config.settings
|
||||
and config.settings.Lua
|
||||
and config.settings.Lua.workspace
|
||||
and config.settings.Lua.workspace.library
|
||||
or {}
|
||||
|
||||
local ignoreDir = config.settings
|
||||
and config.settings.Lua
|
||||
and config.settings.Lua.workspace
|
||||
and config.settings.Lua.workspace.ignoreDir
|
||||
or {}
|
||||
|
||||
if opts.library.enabled then
|
||||
config.handlers = vim.tbl_extend("force", {}, config.handlers or {})
|
||||
config.handlers["workspace/configuration"] = config.handlers["workspace/configuration"]
|
||||
or function(err, result, ctx, cfg)
|
||||
local ret = vim.lsp.handlers["workspace/configuration"](err, result, ctx, cfg)
|
||||
ret = vim.deepcopy(ret)
|
||||
-- when scopeUri is not set, then the requested config is for the fallback scope
|
||||
-- Don't set workspace libraries for the fallback scope
|
||||
-- Thanks to: https://github.com/LuaLS/lua-language-server/issues/1596#issuecomment-1855087288
|
||||
for i, item in ipairs(result.items) do
|
||||
if type(ret[i]) == "table" then
|
||||
if not item.scopeUri and ret[i].workspace then
|
||||
ret[i].workspace.library = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
config.settings =
|
||||
vim.tbl_deep_extend("force", config.settings or {}, require("neodev.luals").setup(opts, config.settings).settings)
|
||||
for _, lib in ipairs(library) do
|
||||
table.insert(config.settings.Lua.workspace.library, lib)
|
||||
end
|
||||
|
||||
if require("neodev.config").options.pathStrict and lua_root then
|
||||
table.insert(config.settings.Lua.workspace.library, lua_root)
|
||||
end
|
||||
|
||||
for _, dir in ipairs(ignoreDir) do
|
||||
table.insert(config.settings.Lua.workspace.ignoreDir, dir)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,110 @@
|
||||
local config = require("neodev.config")
|
||||
|
||||
local M = {}
|
||||
|
||||
---@param opts LuaDevOptions
|
||||
function M.library(opts)
|
||||
opts = config.merge(opts)
|
||||
local ret = {}
|
||||
|
||||
if opts.library.types then
|
||||
table.insert(ret, config.types())
|
||||
end
|
||||
|
||||
local function add(lib, filter)
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
for _, p in ipairs(vim.fn.expand(lib .. "/lua", false, true)) do
|
||||
local plugin_name = vim.fn.fnamemodify(p, ":h:t")
|
||||
p = vim.loop.fs_realpath(p)
|
||||
if p and (not filter or filter[plugin_name]) then
|
||||
if config.options.pathStrict then
|
||||
table.insert(ret, p)
|
||||
else
|
||||
table.insert(ret, vim.fn.fnamemodify(p, ":h"))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if opts.library.runtime then
|
||||
add(type(opts.library.runtime) == "string" and opts.library.runtime or "$VIMRUNTIME")
|
||||
end
|
||||
|
||||
if opts.library.plugins then
|
||||
---@type table<string, boolean>
|
||||
local filter
|
||||
if type(opts.library.plugins) == "table" then
|
||||
filter = {}
|
||||
for _, p in pairs(opts.library.plugins) do
|
||||
filter[p] = true
|
||||
end
|
||||
end
|
||||
for _, site in pairs(vim.split(vim.o.packpath, ",")) do
|
||||
add(site .. "/pack/*/opt/*", filter)
|
||||
add(site .. "/pack/*/start/*", filter)
|
||||
end
|
||||
-- add support for lazy.nvim
|
||||
if package.loaded["lazy"] then
|
||||
for _, plugin in ipairs(require("lazy").plugins()) do
|
||||
add(plugin.dir, filter)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
---@param settings? lspconfig.settings.lua_ls
|
||||
function M.path(settings)
|
||||
if config.options.pathStrict then
|
||||
return { "?.lua", "?/init.lua" }
|
||||
end
|
||||
|
||||
settings = settings or {}
|
||||
local runtime = settings.Lua and settings.Lua.runtime or {}
|
||||
local meta = runtime.meta or "${version} ${language} ${encoding}"
|
||||
meta = meta:gsub("%${version}", runtime.version or "LuaJIT")
|
||||
meta = meta:gsub("%${language}", "en-us")
|
||||
meta = meta:gsub("%${encoding}", runtime.fileEncoding or "utf8")
|
||||
|
||||
return {
|
||||
-- paths for builtin libraries
|
||||
("meta/%s/?.lua"):format(meta),
|
||||
("meta/%s/?/init.lua"):format(meta),
|
||||
-- paths for meta/3rd libraries
|
||||
"library/?.lua",
|
||||
"library/?/init.lua",
|
||||
-- Neovim lua files, config and plugins
|
||||
"lua/?.lua",
|
||||
"lua/?/init.lua",
|
||||
}
|
||||
end
|
||||
|
||||
---@param opts? LuaDevOptions
|
||||
---@param settings? lspconfig.settings.lua_ls
|
||||
function M.setup(opts, settings)
|
||||
opts = config.merge(opts)
|
||||
return {
|
||||
---@type lspconfig.settings.lua_ls
|
||||
settings = {
|
||||
Lua = {
|
||||
runtime = {
|
||||
version = "LuaJIT",
|
||||
path = M.path(settings),
|
||||
pathStrict = config.options.pathStrict,
|
||||
},
|
||||
---@diagnostic disable-next-line: undefined-field
|
||||
completion = opts.snippet and { callSnippet = "Replace" } or nil,
|
||||
workspace = {
|
||||
-- Make the server aware of Neovim runtime files
|
||||
library = M.library(opts),
|
||||
-- when pathStrict=false, we need to add the other types to ignoreDir,
|
||||
-- otherwise they get indexed
|
||||
ignoreDir = { config.version() == "stable" and "types/nightly" or "types/stable", "lua" },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,87 @@
|
||||
local config = require("neodev.config")
|
||||
|
||||
local M = {}
|
||||
|
||||
--- find the root directory that has /lua
|
||||
---@param path string?
|
||||
---@return string?
|
||||
function M.find_root(path)
|
||||
path = path or vim.api.nvim_buf_get_name(0)
|
||||
return vim.fs.find({ "lua" }, { path = path, upward = true, type = "directory" })[1]
|
||||
end
|
||||
|
||||
function M.fetch(url)
|
||||
local fd = io.popen(string.format("curl -s -k %q", url))
|
||||
if not fd then
|
||||
error(("Could not download %s"):format(url))
|
||||
end
|
||||
local ret = fd:read("*a")
|
||||
fd:close()
|
||||
return ret
|
||||
end
|
||||
|
||||
function M.is_nvim_config()
|
||||
local path = vim.loop.fs_realpath(vim.api.nvim_buf_get_name(0))
|
||||
if path then
|
||||
path = vim.fs.normalize(path)
|
||||
local config_root = vim.loop.fs_realpath(vim.fn.stdpath("config")) or vim.fn.stdpath("config")
|
||||
config_root = vim.fs.normalize(config_root)
|
||||
return path:find(config_root, 1, true) == 1
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function M.keys(tbl)
|
||||
local ret = vim.tbl_keys(tbl)
|
||||
table.sort(ret)
|
||||
return ret
|
||||
end
|
||||
|
||||
---@generic K
|
||||
---@generic V
|
||||
---@param tbl table<K, V>
|
||||
---@param fn fun(key: K, value: V)
|
||||
function M.for_each(tbl, fn)
|
||||
local keys = M.keys(tbl)
|
||||
for _, key in ipairs(keys) do
|
||||
fn(key, tbl[key])
|
||||
end
|
||||
end
|
||||
|
||||
---@param file string
|
||||
---@param flags? string
|
||||
---@return string
|
||||
function M.read_file(file, flags)
|
||||
local fd = io.open(file, "r" .. (flags or ""))
|
||||
if not fd then
|
||||
error(("Could not open file %s for reading"):format(file))
|
||||
end
|
||||
local data = fd:read("*a")
|
||||
fd:close()
|
||||
return data
|
||||
end
|
||||
|
||||
function M.write_file(file, data)
|
||||
local fd = io.open(file, "w+")
|
||||
if not fd then
|
||||
error(("Could not open file %s for writing"):format(file))
|
||||
end
|
||||
fd:write(data)
|
||||
fd:close()
|
||||
end
|
||||
|
||||
function M.debug(msg)
|
||||
if config.options.debug then
|
||||
M.error(msg)
|
||||
end
|
||||
end
|
||||
|
||||
function M.error(msg)
|
||||
vim.notify_once(msg, vim.log.levels.ERROR, { title = "neodev.nvim" })
|
||||
end
|
||||
|
||||
function M.warn(msg)
|
||||
vim.notify_once(msg, vim.log.levels.WARN, { title = "neodev.nvim" })
|
||||
end
|
||||
|
||||
return M
|
||||
Reference in New Issue
Block a user