mirror of
https://github.com/neovim/neovim.git
synced 2024-12-19 10:45:16 -07:00
refactor(gen_lsp.lua): add typing for the LSP protocol JSON data model
Enhance readability and intellisense by incorporating type annotations. Types are not very strict and may not encompass th entire LSP Protocol metamodel; the scope is up to what's relevant for generating type annotations for LSP (`_meta/protocol.lua`). Based on the model schema: https://raw.githubusercontent.com/microsoft/language-server-protocol/gh-pages/_specifications/lsp/3.18/metaModel/metaModel.schema.json No behavioral changes (and hence no diff on _meta/protocol.lua) should exist in this commit.
This commit is contained in:
parent
3767468b96
commit
2f43af6423
@ -24,7 +24,17 @@ local function tofile(fname, text)
|
||||
end
|
||||
end
|
||||
|
||||
---@param opt gen_lsp._opt
|
||||
--- The LSP protocol JSON data (it's partial, non-exhaustive).
|
||||
--- https://raw.githubusercontent.com/microsoft/language-server-protocol/gh-pages/_specifications/lsp/3.18/metaModel/metaModel.schema.json
|
||||
--- @class vim._gen_lsp.Protocol
|
||||
--- @field requests vim._gen_lsp.Request[]
|
||||
--- @field notifications vim._gen_lsp.Notification[]
|
||||
--- @field structures vim._gen_lsp.Structure[]
|
||||
--- @field enumerations vim._gen_lsp.Enumeration[]
|
||||
--- @field typeAliases vim._gen_lsp.TypeAlias[]
|
||||
|
||||
---@param opt vim._gen_lsp.opt
|
||||
---@return vim._gen_lsp.Protocol
|
||||
local function read_json(opt)
|
||||
local uri = 'https://raw.githubusercontent.com/microsoft/language-server-protocol/gh-pages/_specifications/lsp/'
|
||||
.. opt.version
|
||||
@ -46,6 +56,7 @@ local function name(s)
|
||||
return s:gsub('^%$', 'dollar'):gsub('/', '_')
|
||||
end
|
||||
|
||||
---@param protocol vim._gen_lsp.Protocol
|
||||
local function gen_methods(protocol)
|
||||
local output = {
|
||||
'-- Generated by gen_lsp.lua, keep at end of file.',
|
||||
@ -56,6 +67,32 @@ local function gen_methods(protocol)
|
||||
}
|
||||
local indent = (' '):rep(2)
|
||||
|
||||
--- @class vim._gen_lsp.Request
|
||||
--- @field deprecated? string
|
||||
--- @field documentation? string
|
||||
--- @field messageDirection string
|
||||
--- @field method string
|
||||
--- @field params? any
|
||||
--- @field proposed? boolean
|
||||
--- @field registrationMethod? string
|
||||
--- @field registrationOptions? any
|
||||
--- @field since? string
|
||||
|
||||
--- @class vim._gen_lsp.Notification
|
||||
--- @field deprecated? string
|
||||
--- @field documentation? string
|
||||
--- @field errorData? any
|
||||
--- @field messageDirection string
|
||||
--- @field method string
|
||||
--- @field params? any[]
|
||||
--- @field partialResult? any
|
||||
--- @field proposed? boolean
|
||||
--- @field registrationMethod? string
|
||||
--- @field registrationOptions? any
|
||||
--- @field result any
|
||||
--- @field since? string
|
||||
|
||||
---@type (vim._gen_lsp.Request|vim._gen_lsp.Notification)[]
|
||||
local all = vim.list_extend(protocol.requests, protocol.notifications)
|
||||
table.sort(all, function(a, b)
|
||||
return name(a.method) < name(b.method)
|
||||
@ -106,14 +143,15 @@ return protocol
|
||||
vim.cmd.write()
|
||||
end
|
||||
|
||||
---@class gen_lsp._opt
|
||||
---@class vim._gen_lsp.opt
|
||||
---@field output_file string
|
||||
---@field version string
|
||||
---@field methods boolean
|
||||
|
||||
---@param opt gen_lsp._opt
|
||||
---@param opt vim._gen_lsp.opt
|
||||
function M.gen(opt)
|
||||
local protocol = read_json(opt) --- @type table
|
||||
--- @type vim._gen_lsp.Protocol
|
||||
local protocol = read_json(opt)
|
||||
|
||||
if opt.methods then
|
||||
gen_methods(protocol)
|
||||
@ -144,6 +182,7 @@ function M.gen(opt)
|
||||
|
||||
local anonymous_num = 0
|
||||
|
||||
---@type string[]
|
||||
local anonym_classes = {}
|
||||
|
||||
local simple_types = {
|
||||
@ -154,32 +193,65 @@ function M.gen(opt)
|
||||
'decimal',
|
||||
}
|
||||
|
||||
--- @class vim._gen_lsp.Type
|
||||
--- @field kind string a common field for all Types.
|
||||
--- @field name? string for ReferenceType, BaseType
|
||||
--- @field element? any for ArrayType
|
||||
--- @field items? vim._gen_lsp.Type[] for OrType, AndType
|
||||
--- @field key? vim._gen_lsp.Type for MapType
|
||||
--- @field value? string|vim._gen_lsp.Type for StringLiteralType, MapType, StructureLiteralType
|
||||
|
||||
---@param type vim._gen_lsp.Type
|
||||
---@return string
|
||||
local function parse_type(type)
|
||||
-- ReferenceType | BaseType
|
||||
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
|
||||
|
||||
-- ArrayType
|
||||
elseif type.kind == 'array' then
|
||||
return parse_type(type.element) .. '[]'
|
||||
|
||||
-- OrType
|
||||
elseif type.kind == 'or' then
|
||||
local val = ''
|
||||
for _, item in ipairs(type.items) do
|
||||
val = val .. parse_type(item) .. '|'
|
||||
val = val .. parse_type(item) .. '|' --[[ @as string ]]
|
||||
end
|
||||
val = val:sub(0, -2)
|
||||
return val
|
||||
|
||||
-- StringLiteralType
|
||||
elseif type.kind == 'stringLiteral' then
|
||||
return '"' .. type.value .. '"'
|
||||
|
||||
-- MapType
|
||||
elseif type.kind == 'map' then
|
||||
return 'table<' .. parse_type(type.key) .. ', ' .. parse_type(type.value) .. '>'
|
||||
local key = assert(type.key)
|
||||
local value = type.value --[[ @as vim._gen_lsp.Type ]]
|
||||
return 'table<' .. parse_type(key) .. ', ' .. parse_type(value) .. '>'
|
||||
|
||||
-- StructureLiteralType
|
||||
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
|
||||
|
||||
--- @class vim._gen_lsp.StructureLiteral translated to anonymous @class.
|
||||
--- @field deprecated? string
|
||||
--- @field description? string
|
||||
--- @field properties vim._gen_lsp.Property[]
|
||||
--- @field proposed? boolean
|
||||
--- @field since? string
|
||||
|
||||
---@type vim._gen_lsp.StructureLiteral
|
||||
local structural_literal = assert(type.value) --[[ @as vim._gen_lsp.StructureLiteral ]]
|
||||
for _, field in ipairs(structural_literal.properties) do
|
||||
if field.documentation then
|
||||
field.documentation = field.documentation:gsub('\n', '\n---')
|
||||
anonym[#anonym + 1] = '---' .. field.documentation
|
||||
@ -195,6 +267,8 @@ function M.gen(opt)
|
||||
anonym_classes[#anonym_classes + 1] = line
|
||||
end
|
||||
return 'anonym' .. anonymous_num
|
||||
|
||||
-- TupleType
|
||||
elseif type.kind == 'tuple' then
|
||||
local tuple = '{ '
|
||||
for i, value in ipairs(type.items) do
|
||||
@ -204,10 +278,20 @@ function M.gen(opt)
|
||||
tuple = tuple:sub(0, -3)
|
||||
return tuple .. ' }'
|
||||
end
|
||||
vim.print(type)
|
||||
|
||||
vim.print('WARNING: Unknown type ', type)
|
||||
return ''
|
||||
end
|
||||
|
||||
--- @class vim._gen_lsp.Structure translated to @class
|
||||
--- @field deprecated? string
|
||||
--- @field documentation? string
|
||||
--- @field extends? { kind: string, name: string }[]
|
||||
--- @field mixins? { kind: string, name: string }[]
|
||||
--- @field name string
|
||||
--- @field properties? vim._gen_lsp.Property[] members, translated to @field
|
||||
--- @field proposed? boolean
|
||||
--- @field since? string
|
||||
for _, structure in ipairs(protocol.structures) do
|
||||
if structure.documentation then
|
||||
structure.documentation = structure.documentation:gsub('\n', '\n---')
|
||||
@ -225,6 +309,15 @@ function M.gen(opt)
|
||||
else
|
||||
output[#output + 1] = '---@class lsp.' .. structure.name
|
||||
end
|
||||
|
||||
--- @class vim._gen_lsp.Property translated to @field
|
||||
--- @field deprecated? string
|
||||
--- @field documentation? string
|
||||
--- @field name string
|
||||
--- @field optional? boolean
|
||||
--- @field proposed? boolean
|
||||
--- @field since? string
|
||||
--- @field type { kind: string, name: string }
|
||||
for _, field in ipairs(structure.properties or {}) do
|
||||
if field.documentation then
|
||||
field.documentation = field.documentation:gsub('\n', '\n---')
|
||||
@ -239,6 +332,14 @@ function M.gen(opt)
|
||||
output[#output + 1] = ''
|
||||
end
|
||||
|
||||
--- @class vim._gen_lsp.Enumeration translated to @enum
|
||||
--- @field deprecated string?
|
||||
--- @field documentation string?
|
||||
--- @field name string?
|
||||
--- @field proposed boolean?
|
||||
--- @field since string?
|
||||
--- @field suportsCustomValues boolean?
|
||||
--- @field values { name: string, value: string, documentation?: string, since?: string }[]
|
||||
for _, enum in ipairs(protocol.enumerations) do
|
||||
if enum.documentation then
|
||||
enum.documentation = enum.documentation:gsub('\n', '\n---')
|
||||
@ -256,6 +357,13 @@ function M.gen(opt)
|
||||
output[#output + 1] = ''
|
||||
end
|
||||
|
||||
--- @class vim._gen_lsp.TypeAlias translated to @alias
|
||||
--- @field deprecated? string?
|
||||
--- @field documentation? string
|
||||
--- @field name string
|
||||
--- @field proposed? boolean
|
||||
--- @field since? string
|
||||
--- @field type vim._gen_lsp.Type
|
||||
for _, alias in ipairs(protocol.typeAliases) do
|
||||
if alias.documentation then
|
||||
alias.documentation = alias.documentation:gsub('\n', '\n---')
|
||||
@ -274,6 +382,7 @@ function M.gen(opt)
|
||||
output[#output + 1] = ''
|
||||
end
|
||||
|
||||
-- anonymous classes
|
||||
for _, line in ipairs(anonym_classes) do
|
||||
output[#output + 1] = line
|
||||
end
|
||||
@ -281,6 +390,7 @@ function M.gen(opt)
|
||||
tofile(opt.output_file, table.concat(output, '\n'))
|
||||
end
|
||||
|
||||
---@type vim._gen_lsp.opt
|
||||
local opt = {
|
||||
output_file = 'runtime/lua/vim/lsp/_meta/protocol.lua',
|
||||
version = DEFAULT_LSP_VERSION,
|
||||
|
Loading…
Reference in New Issue
Block a user