mirror of https://github.com/folke/neoconf.nvim
220 lines
5.4 KiB
Lua
220 lines
5.4 KiB
Lua
local util = require("neoconf.util")
|
|
|
|
local M = {}
|
|
|
|
M.class_name = ""
|
|
M.lines = {}
|
|
|
|
function M.table_key(str)
|
|
if str:match("[^%a_]") then
|
|
return "[" .. vim.inspect(str) .. "]"
|
|
end
|
|
return str
|
|
end
|
|
|
|
function M.comment(desc, prefix)
|
|
if desc then
|
|
prefix = (prefix or "") .. "-- "
|
|
return prefix .. desc:gsub("\n", "\n" .. prefix)
|
|
end
|
|
end
|
|
|
|
function M.add_desc(lines, prop, prefix)
|
|
local ret = prop.markdownDescription or prop.description
|
|
if type(ret) == "table" and ret.message then
|
|
ret = ret.message
|
|
end
|
|
if prop.default then
|
|
if prop.default == vim.NIL then
|
|
prop.default = nil
|
|
end
|
|
if type(prop.default) == "table" and vim.tbl_isempty(prop.default) then
|
|
prop.default = {}
|
|
end
|
|
ret = (ret and (ret .. "\n\n") or "") .. "```lua\ndefault = " .. vim.inspect(prop.default) .. "\n```"
|
|
end
|
|
if ret then
|
|
table.insert(lines, M.comment(ret, prefix))
|
|
end
|
|
end
|
|
|
|
function M.fix_props(node)
|
|
return node.leaf and node
|
|
or {
|
|
type = "object",
|
|
properties = vim.tbl_map(function(child)
|
|
return M.fix_props(child)
|
|
end, node),
|
|
}
|
|
end
|
|
|
|
function M.get_class(name)
|
|
if name == M.class_name then
|
|
return name
|
|
end
|
|
local ret = { "_", M.class_name }
|
|
for word in string.gmatch(name, "([^_]+)") do
|
|
table.insert(ret, word:sub(1, 1):upper() .. word:sub(2))
|
|
end
|
|
return table.concat(ret, ".")
|
|
end
|
|
|
|
function M.get_type(prop)
|
|
if prop.enum then
|
|
return table.concat(
|
|
vim.tbl_map(function(e)
|
|
return vim.inspect(e)
|
|
end, prop.enum),
|
|
" | "
|
|
)
|
|
end
|
|
local types = type(prop.type) == "table" and prop.type or { prop.type }
|
|
if vim.tbl_isempty(types) and type(prop.anyOf) == "table" then
|
|
return table.concat(
|
|
vim.tbl_map(function(p)
|
|
return M.get_type(p)
|
|
end, prop.anyOf),
|
|
"|"
|
|
)
|
|
end
|
|
types = vim.tbl_map(function(t)
|
|
if t == "null" then
|
|
return
|
|
end
|
|
if t == "array" then
|
|
if prop.items and prop.items.type then
|
|
if type(prop.items.type) == "table" then
|
|
prop.items.type = "any"
|
|
end
|
|
return prop.items.type .. "[]"
|
|
end
|
|
return "any[]"
|
|
end
|
|
if t == "object" then
|
|
return "table"
|
|
end
|
|
return t
|
|
end, types)
|
|
if vim.tbl_isempty(types) then
|
|
types = { "any" }
|
|
end
|
|
return table.concat(util.flatten(types), "|")
|
|
end
|
|
|
|
function M.process_object(name, prop)
|
|
local lines = {}
|
|
M.add_desc(lines, prop)
|
|
table.insert(lines, "---@class " .. M.get_class(name))
|
|
if prop.properties then
|
|
local props = vim.tbl_keys(prop.properties)
|
|
table.sort(props)
|
|
for _, field in ipairs(props) do
|
|
local child = prop.properties[field]
|
|
M.add_desc(lines, child)
|
|
|
|
if child.type == "object" and child.properties then
|
|
table.insert(lines, "---@field " .. field .. " " .. M.get_class(field))
|
|
M.process_object(field, child)
|
|
else
|
|
table.insert(lines, "---@field " .. field .. " " .. M.get_type(child))
|
|
end
|
|
end
|
|
end
|
|
table.insert(M.lines, "")
|
|
vim.list_extend(M.lines, lines)
|
|
end
|
|
|
|
function M.process_prop(lines, name, prop)
|
|
if prop.type == "object" then
|
|
error("should not happen")
|
|
end
|
|
|
|
table.insert(lines, " " .. M.table_key(name) .. " = " .. vim.inspect(prop.default) .. ",")
|
|
end
|
|
|
|
function M.build_annotations(name)
|
|
local file = util.path("schemas/" .. name .. ".json")
|
|
local json = util.json_decode(util.read_file(file)) or {}
|
|
M.class_name = "lspconfig.settings." .. name
|
|
|
|
local schema = require("neoconf.settings").new()
|
|
for key, prop in pairs(json.properties) do
|
|
prop.leaf = true
|
|
schema:set(key, prop)
|
|
end
|
|
|
|
M.process_object(M.class_name, M.fix_props(schema:get()))
|
|
end
|
|
|
|
function M.build_lspconfig()
|
|
local str = [[---@meta
|
|
|
|
---@class _.lspconfig.options
|
|
---@field root_dir fun(filename, bufnr): string|nil
|
|
---@field name string
|
|
---@field filetypes string[] | nil
|
|
---@field autostart boolean
|
|
---@field single_file_support boolean
|
|
---@field on_new_config fun(new_config, new_root_dir)
|
|
---@field capabilities table
|
|
---@field cmd string[]
|
|
---@field handlers table<string, fun()>
|
|
---@field init_options table
|
|
---@field on_attach fun(client, bufnr)
|
|
|
|
---@module 'lspconfig'
|
|
local lspconfig
|
|
|
|
]]
|
|
|
|
local index = vim.tbl_keys(require("neoconf.build.schemas").get_schemas())
|
|
table.sort(index)
|
|
|
|
for _, name in ipairs(index) do
|
|
str = str
|
|
.. ([[
|
|
|
|
---@class lspconfig.options.%s: _.lspconfig.options
|
|
---@field settings lspconfig.settings.%s
|
|
|
|
lspconfig.%s = {
|
|
---@param options lspconfig.options.%s
|
|
setup = function(options) end,
|
|
}
|
|
]]):format(name, name, name, name)
|
|
end
|
|
|
|
str = str .. "\n---@class lspconfig.options\n"
|
|
for _, name in ipairs(index) do
|
|
str = str .. ("---@field %s lspconfig.options.%s\n"):format(name, name)
|
|
end
|
|
|
|
str = str .. "\n---@class lspconfig.settings\n"
|
|
for _, name, _ in ipairs(index) do
|
|
str = str .. ("---@field %s lspconfig.settings.%s\n"):format(name, name)
|
|
end
|
|
|
|
str = str .. "\n\n return lspconfig"
|
|
util.write_file("types/lua/lspconfig.lua", str)
|
|
end
|
|
|
|
function M.build()
|
|
M.lines = { "---@meta\n" }
|
|
local index = vim.tbl_keys(require("neoconf.build.schemas").get_schemas())
|
|
table.sort(index)
|
|
for _, name in ipairs(index) do
|
|
local ok, err = pcall(M.build_annotations, name)
|
|
if not ok then
|
|
print("error building " .. name .. ": " .. err)
|
|
end
|
|
end
|
|
|
|
local lines = vim.tbl_filter(function(v)
|
|
return v ~= nil
|
|
end, M.lines)
|
|
util.write_file("types/lsp.lua", table.concat(lines, "\n"))
|
|
M.build_lspconfig()
|
|
end
|
|
|
|
return M
|