aboutsummaryrefslogtreecommitdiff
path: root/scripts/lsp_types.lua
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/lsp_types.lua')
-rw-r--r--scripts/lsp_types.lua207
1 files changed, 207 insertions, 0 deletions
diff --git a/scripts/lsp_types.lua b/scripts/lsp_types.lua
new file mode 100644
index 0000000000..8f3ed811d6
--- /dev/null
+++ b/scripts/lsp_types.lua
@@ -0,0 +1,207 @@
+--[[
+Generates lua-ls annotations for lsp
+USAGE:
+nvim -l scripts/lsp_types.lua gen --runtime/lua/vim/lsp/types/protocol.lua
+--]]
+
+local M = {}
+
+local function tofile(fname, text)
+ local f = io.open(fname, 'w')
+ if not f then
+ error(('failed to write: %s'):format(f))
+ else
+ f:write(text)
+ f:close()
+ end
+end
+
+function M.gen(opt)
+ if vim.loop.fs_stat('./lsp.json') then
+ vim.fn.delete('./lsp.json')
+ end
+ vim.fn.system({
+ 'curl',
+ 'https://raw.githubusercontent.com/microsoft/lsprotocol/main/generator/lsp.json',
+ '-o',
+ './lsp.json',
+ })
+ local protocol = vim.fn.json_decode(vim.fn.readfile('./lsp.json'))
+ vim.fn.delete('./lsp.json')
+ local output_file = opt[1]
+ protocol = protocol or {}
+ local output = {
+ '--[[',
+ 'This file is autogenerated from scripts/lsp_types.lua',
+ 'Regenerate:',
+ [=[nvim -l scripts/lsp_types.lua gen --runtime/lua/vim/lsp/types/protocol.lua]=],
+ '--]]',
+ '',
+ '---@alias lsp.null nil',
+ '---@alias uinteger integer',
+ '---@alias lsp.decimal number',
+ '---@alias lsp.DocumentUri string',
+ '---@alias lsp.URI string',
+ '---@alias lsp.LSPObject table<string, lsp.LSPAny>',
+ '---@alias lsp.LSPArray lsp.LSPAny[]',
+ '---@alias lsp.LSPAny lsp.LSPObject|lsp.LSPArray|string|number|boolean|nil',
+ '',
+ }
+
+ local anonymous_num = 0
+
+ local anonym_classes = {}
+
+ local simple_types = {
+ 'string',
+ 'boolean',
+ 'integer',
+ 'uinteger',
+ 'decimal',
+ }
+
+ local function parse_type(type)
+ if type.kind == 'reference' or type.kind == 'base' then
+ if vim.tbl_contains(simple_types, type.name) then
+ return type.name
+ end
+ return 'lsp.' .. type.name
+ elseif type.kind == 'array' then
+ return parse_type(type.element) .. '[]'
+ elseif type.kind == 'or' then
+ local val = ''
+ for _, item in ipairs(type.items) do
+ val = val .. parse_type(item) .. '|'
+ end
+ val = val:sub(0, -2)
+ return val
+ elseif type.kind == 'stringLiteral' then
+ return '"' .. type.value .. '"'
+ elseif type.kind == 'map' then
+ return 'table<' .. parse_type(type.key) .. ', ' .. parse_type(type.value) .. '>'
+ elseif type.kind == 'literal' then
+ -- can I use ---@param disabled? {reason: string}
+ -- use | to continue the inline class to be able to add docs
+ -- https://github.com/LuaLS/lua-language-server/issues/2128
+ anonymous_num = anonymous_num + 1
+ local anonym = { '---@class anonym' .. anonymous_num }
+ for _, field in ipairs(type.value.properties) do
+ if field.documentation then
+ field.documentation = field.documentation:gsub('\n', '\n---')
+ anonym[#anonym + 1] = '---' .. field.documentation
+ end
+ anonym[#anonym + 1] = '---@field '
+ .. field.name
+ .. (field.optional and '?' or '')
+ .. ' '
+ .. parse_type(field.type)
+ end
+ anonym[#anonym + 1] = ''
+ for _, line in ipairs(anonym) do
+ anonym_classes[#anonym_classes + 1] = line
+ end
+ return 'anonym' .. anonymous_num
+ elseif type.kind == 'tuple' then
+ local tuple = '{ '
+ for i, value in ipairs(type.items) do
+ tuple = tuple .. '[' .. i .. ']: ' .. parse_type(value) .. ', '
+ end
+ -- remove , at the end
+ tuple = tuple:sub(0, -3)
+ return tuple .. ' }'
+ end
+ vim.print(type)
+ return ''
+ end
+
+ for _, structure in ipairs(protocol.structures) do
+ if structure.documentation then
+ structure.documentation = structure.documentation:gsub('\n', '\n---')
+ output[#output + 1] = '---' .. structure.documentation
+ end
+ if structure.extends then
+ local class_string = '---@class lsp.'
+ .. structure.name
+ .. ': '
+ .. parse_type(structure.extends[1])
+ for _, mixin in ipairs(structure.mixins or {}) do
+ class_string = class_string .. ', ' .. parse_type(mixin)
+ end
+ output[#output + 1] = class_string
+ else
+ output[#output + 1] = '---@class lsp.' .. structure.name
+ end
+ for _, field in ipairs(structure.properties or {}) do
+ if field.documentation then
+ field.documentation = field.documentation:gsub('\n', '\n---')
+ output[#output + 1] = '---' .. field.documentation
+ end
+ output[#output + 1] = '---@field '
+ .. field.name
+ .. (field.optional and '?' or '')
+ .. ' '
+ .. parse_type(field.type)
+ end
+ output[#output + 1] = ''
+ end
+
+ for _, enum in ipairs(protocol.enumerations) do
+ if enum.documentation then
+ enum.documentation = enum.documentation:gsub('\n', '\n---')
+ output[#output + 1] = '---' .. enum.documentation
+ end
+ local enum_type = '---@alias lsp.' .. enum.name
+ for _, value in ipairs(enum.values) do
+ enum_type = enum_type
+ .. '\n---| '
+ .. (type(value.value) == 'string' and '"' .. value.value .. '"' or value.value)
+ .. ' # '
+ .. value.name
+ end
+ output[#output + 1] = enum_type
+ output[#output + 1] = ''
+ end
+
+ for _, alias in ipairs(protocol.typeAliases) do
+ if alias.documentation then
+ alias.documentation = alias.documentation:gsub('\n', '\n---')
+ output[#output + 1] = '---' .. alias.documentation
+ end
+ if alias.type.kind == 'or' then
+ local alias_type = '---@alias lsp.' .. alias.name .. ' '
+ for _, item in ipairs(alias.type.items) do
+ alias_type = alias_type .. parse_type(item) .. '|'
+ end
+ alias_type = alias_type:sub(0, -2)
+ output[#output + 1] = alias_type
+ else
+ output[#output + 1] = '---@alias lsp.' .. alias.name .. ' ' .. parse_type(alias.type)
+ end
+ output[#output + 1] = ''
+ end
+
+ for _, line in ipairs(anonym_classes) do
+ output[#output + 1] = line
+ end
+
+ tofile(output_file, table.concat(output, '\n'))
+end
+
+local opt = {}
+
+local index = 1
+for _, a in ipairs(arg) do
+ if vim.startswith(a, '--') then
+ local name = a:sub(3)
+ opt[index] = name
+ index = index + 1
+ end
+end
+
+for _, a in ipairs(arg) do
+ if M[a] then
+ M[a](opt)
+ end
+end
+
+return M