mirror of
https://github.com/neovim/neovim.git
synced 2024-12-29 14:41:06 -07:00
fix(gen_lsp.lua): improve type name, and fix wrong type inheritance
Style improvements: 1. Anonymous classes derived from `StructureLiteralType` should have a better name. The class name can be also nested. Examples: ```diff ----@field serverInfo? anonym1 +---@field serverInfo? lsp._anonym1.serverInfo ``` ```diff ----@field insertTextModeSupport? anonym26 +---@field insertTextModeSupport? lsp._anonym26.completionItem.insertTextModeSupport ``` 2. Add one separate empty line before each `@field` definition. Without these, empty lines the doc can look confusing because descriptions also may contain empty lines. See `lsp.CompletionItem` for example: ```lua ---The kind of this completion item. Based of the kind ---an icon is chosen by the editor. ---@field kind? lsp.CompletionItemKind ---Tags for this completion item. --- ---@since 3.15.0 ---@field tags? lsp.CompletionItemTag[] ``` It might feel like "Tags for this completion item" belongs to `kind`, not `tags` due to the lack of separator blank lines. The following (after this commit) should look much better: ```diff ---The kind of this completion item. Based of the kind ---an icon is chosen by the editor. ---@field kind? lsp.CompletionItemKind +--- ---Tags for this completion item. --- ---@since 3.15.0 ---@field tags? lsp.CompletionItemTag[] ``` 3. Escape some LSP-specific annotations that can't be recognized by lua-ls. It'd be better to make them visible in LSP hover doc windows. Example: `@sample ...`. Fixes: 1. A type may extend from more than one base types (as well as mixin types). Previously only the first base class was being considered, resulting incomplete base classes for `@class` definitions. Example: `InlayHintOptions` (should have both of `resolveProvider` and `workDoneProgress`, the latter is from `WorkDoneProgressOptions`) ```diff ----@class lsp.InlayHintOptions +---@class lsp.InlayHintOptions: lsp.WorkDoneProgressOptions ``` 2. Remove `<200b>` (zero-width space) unicode characters. 3. Add the missing newline at EOF.
This commit is contained in:
parent
2f43af6423
commit
6c35fb421e
File diff suppressed because it is too large
Load Diff
@ -51,7 +51,7 @@ local function read_json(opt)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Gets the Lua symbol for a given fully-qualified LSP method name.
|
-- Gets the Lua symbol for a given fully-qualified LSP method name.
|
||||||
local function name(s)
|
local function to_luaname(s)
|
||||||
-- "$/" prefix is special: https://microsoft.github.io/language-server-protocol/specification/#dollarRequests
|
-- "$/" prefix is special: https://microsoft.github.io/language-server-protocol/specification/#dollarRequests
|
||||||
return s:gsub('^%$', 'dollar'):gsub('/', '_')
|
return s:gsub('^%$', 'dollar'):gsub('/', '_')
|
||||||
end
|
end
|
||||||
@ -95,7 +95,7 @@ local function gen_methods(protocol)
|
|||||||
---@type (vim._gen_lsp.Request|vim._gen_lsp.Notification)[]
|
---@type (vim._gen_lsp.Request|vim._gen_lsp.Notification)[]
|
||||||
local all = vim.list_extend(protocol.requests, protocol.notifications)
|
local all = vim.list_extend(protocol.requests, protocol.notifications)
|
||||||
table.sort(all, function(a, b)
|
table.sort(all, function(a, b)
|
||||||
return name(a.method) < name(b.method)
|
return to_luaname(a.method) < to_luaname(b.method)
|
||||||
end)
|
end)
|
||||||
for _, item in ipairs(all) do
|
for _, item in ipairs(all) do
|
||||||
if item.method then
|
if item.method then
|
||||||
@ -105,7 +105,7 @@ local function gen_methods(protocol)
|
|||||||
output[#output + 1] = indent .. '--- ' .. docstring
|
output[#output + 1] = indent .. '--- ' .. docstring
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
output[#output + 1] = ("%s%s = '%s',"):format(indent, name(item.method), item.method)
|
output[#output + 1] = ("%s%s = '%s',"):format(indent, to_luaname(item.method), item.method)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
output[#output + 1] = '}'
|
output[#output + 1] = '}'
|
||||||
@ -193,6 +193,16 @@ function M.gen(opt)
|
|||||||
'decimal',
|
'decimal',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
---@param documentation string
|
||||||
|
local _process_documentation = function(documentation)
|
||||||
|
documentation = documentation:gsub('\n', '\n---')
|
||||||
|
-- Remove <200b> (zero-width space) unicode characters: e.g., `**/<200b>*`
|
||||||
|
documentation = documentation:gsub('\226\128\139', '')
|
||||||
|
-- Escape annotations that are not recognized by lua-ls
|
||||||
|
documentation = documentation:gsub('%^---@sample', '---\\@sample')
|
||||||
|
return '---' .. documentation
|
||||||
|
end
|
||||||
|
|
||||||
--- @class vim._gen_lsp.Type
|
--- @class vim._gen_lsp.Type
|
||||||
--- @field kind string a common field for all Types.
|
--- @field kind string a common field for all Types.
|
||||||
--- @field name? string for ReferenceType, BaseType
|
--- @field name? string for ReferenceType, BaseType
|
||||||
@ -202,8 +212,10 @@ function M.gen(opt)
|
|||||||
--- @field value? string|vim._gen_lsp.Type for StringLiteralType, MapType, StructureLiteralType
|
--- @field value? string|vim._gen_lsp.Type for StringLiteralType, MapType, StructureLiteralType
|
||||||
|
|
||||||
---@param type vim._gen_lsp.Type
|
---@param type vim._gen_lsp.Type
|
||||||
|
---@param prefix? string Optional prefix associated with the this type, made of (nested) field name.
|
||||||
|
--- Used to generate class name for structure literal types.
|
||||||
---@return string
|
---@return string
|
||||||
local function parse_type(type)
|
local function parse_type(type, prefix)
|
||||||
-- ReferenceType | BaseType
|
-- ReferenceType | BaseType
|
||||||
if type.kind == 'reference' or type.kind == 'base' then
|
if type.kind == 'reference' or type.kind == 'base' then
|
||||||
if vim.tbl_contains(simple_types, type.name) then
|
if vim.tbl_contains(simple_types, type.name) then
|
||||||
@ -213,13 +225,13 @@ function M.gen(opt)
|
|||||||
|
|
||||||
-- ArrayType
|
-- ArrayType
|
||||||
elseif type.kind == 'array' then
|
elseif type.kind == 'array' then
|
||||||
return parse_type(type.element) .. '[]'
|
return parse_type(type.element, prefix) .. '[]'
|
||||||
|
|
||||||
-- OrType
|
-- OrType
|
||||||
elseif type.kind == 'or' then
|
elseif type.kind == 'or' then
|
||||||
local val = ''
|
local val = ''
|
||||||
for _, item in ipairs(type.items) do
|
for _, item in ipairs(type.items) do
|
||||||
val = val .. parse_type(item) .. '|' --[[ @as string ]]
|
val = val .. parse_type(item, prefix) .. '|' --[[ @as string ]]
|
||||||
end
|
end
|
||||||
val = val:sub(0, -2)
|
val = val:sub(0, -2)
|
||||||
return val
|
return val
|
||||||
@ -232,7 +244,7 @@ function M.gen(opt)
|
|||||||
elseif type.kind == 'map' then
|
elseif type.kind == 'map' then
|
||||||
local key = assert(type.key)
|
local key = assert(type.key)
|
||||||
local value = type.value --[[ @as vim._gen_lsp.Type ]]
|
local value = type.value --[[ @as vim._gen_lsp.Type ]]
|
||||||
return 'table<' .. parse_type(key) .. ', ' .. parse_type(value) .. '>'
|
return 'table<' .. parse_type(key, prefix) .. ', ' .. parse_type(value, prefix) .. '>'
|
||||||
|
|
||||||
-- StructureLiteralType
|
-- StructureLiteralType
|
||||||
elseif type.kind == 'literal' then
|
elseif type.kind == 'literal' then
|
||||||
@ -240,7 +252,14 @@ function M.gen(opt)
|
|||||||
-- use | to continue the inline class to be able to add docs
|
-- use | to continue the inline class to be able to add docs
|
||||||
-- https://github.com/LuaLS/lua-language-server/issues/2128
|
-- https://github.com/LuaLS/lua-language-server/issues/2128
|
||||||
anonymous_num = anonymous_num + 1
|
anonymous_num = anonymous_num + 1
|
||||||
local anonym = { '---@class anonym' .. anonymous_num }
|
local anonymous_classname = 'lsp._anonym' .. anonymous_num
|
||||||
|
if prefix then
|
||||||
|
anonymous_classname = anonymous_classname .. '.' .. prefix
|
||||||
|
end
|
||||||
|
local anonym = vim.tbl_flatten { -- remove nil
|
||||||
|
anonymous_num > 1 and '' or nil,
|
||||||
|
'---@class ' .. anonymous_classname,
|
||||||
|
}
|
||||||
|
|
||||||
--- @class vim._gen_lsp.StructureLiteral translated to anonymous @class.
|
--- @class vim._gen_lsp.StructureLiteral translated to anonymous @class.
|
||||||
--- @field deprecated? string
|
--- @field deprecated? string
|
||||||
@ -252,27 +271,29 @@ function M.gen(opt)
|
|||||||
---@type vim._gen_lsp.StructureLiteral
|
---@type vim._gen_lsp.StructureLiteral
|
||||||
local structural_literal = assert(type.value) --[[ @as vim._gen_lsp.StructureLiteral ]]
|
local structural_literal = assert(type.value) --[[ @as vim._gen_lsp.StructureLiteral ]]
|
||||||
for _, field in ipairs(structural_literal.properties) do
|
for _, field in ipairs(structural_literal.properties) do
|
||||||
|
anonym[#anonym + 1] = '---'
|
||||||
if field.documentation then
|
if field.documentation then
|
||||||
field.documentation = field.documentation:gsub('\n', '\n---')
|
anonym[#anonym + 1] = _process_documentation(field.documentation)
|
||||||
anonym[#anonym + 1] = '---' .. field.documentation
|
|
||||||
end
|
end
|
||||||
anonym[#anonym + 1] = '---@field '
|
anonym[#anonym + 1] = '---@field '
|
||||||
.. field.name
|
.. field.name
|
||||||
.. (field.optional and '?' or '')
|
.. (field.optional and '?' or '')
|
||||||
.. ' '
|
.. ' '
|
||||||
.. parse_type(field.type)
|
.. parse_type(field.type, prefix .. '.' .. field.name)
|
||||||
end
|
end
|
||||||
anonym[#anonym + 1] = ''
|
-- anonym[#anonym + 1] = ''
|
||||||
for _, line in ipairs(anonym) do
|
for _, line in ipairs(anonym) do
|
||||||
|
if line then
|
||||||
anonym_classes[#anonym_classes + 1] = line
|
anonym_classes[#anonym_classes + 1] = line
|
||||||
end
|
end
|
||||||
return 'anonym' .. anonymous_num
|
end
|
||||||
|
return anonymous_classname
|
||||||
|
|
||||||
-- TupleType
|
-- TupleType
|
||||||
elseif type.kind == 'tuple' then
|
elseif type.kind == 'tuple' then
|
||||||
local tuple = '{ '
|
local tuple = '{ '
|
||||||
for i, value in ipairs(type.items) do
|
for i, value in ipairs(type.items) do
|
||||||
tuple = tuple .. '[' .. i .. ']: ' .. parse_type(value) .. ', '
|
tuple = tuple .. '[' .. i .. ']: ' .. parse_type(value, prefix) .. ', '
|
||||||
end
|
end
|
||||||
-- remove , at the end
|
-- remove , at the end
|
||||||
tuple = tuple:sub(0, -3)
|
tuple = tuple:sub(0, -3)
|
||||||
@ -293,22 +314,22 @@ function M.gen(opt)
|
|||||||
--- @field proposed? boolean
|
--- @field proposed? boolean
|
||||||
--- @field since? string
|
--- @field since? string
|
||||||
for _, structure in ipairs(protocol.structures) do
|
for _, structure in ipairs(protocol.structures) do
|
||||||
|
-- output[#output + 1] = ''
|
||||||
if structure.documentation then
|
if structure.documentation then
|
||||||
structure.documentation = structure.documentation:gsub('\n', '\n---')
|
output[#output + 1] = _process_documentation(structure.documentation)
|
||||||
output[#output + 1] = '---' .. structure.documentation
|
|
||||||
end
|
end
|
||||||
if structure.extends then
|
local class_string = ('---@class lsp.%s'):format(structure.name)
|
||||||
local class_string = '---@class lsp.'
|
if structure.extends or structure.mixins then
|
||||||
.. structure.name
|
local inherits_from = table.concat(
|
||||||
.. ': '
|
vim.list_extend(
|
||||||
.. parse_type(structure.extends[1])
|
vim.tbl_map(parse_type, structure.extends or {}),
|
||||||
for _, mixin in ipairs(structure.mixins or {}) do
|
vim.tbl_map(parse_type, structure.mixins or {})
|
||||||
class_string = class_string .. ', ' .. parse_type(mixin)
|
),
|
||||||
|
', '
|
||||||
|
)
|
||||||
|
class_string = class_string .. ': ' .. inherits_from
|
||||||
end
|
end
|
||||||
output[#output + 1] = class_string
|
output[#output + 1] = class_string
|
||||||
else
|
|
||||||
output[#output + 1] = '---@class lsp.' .. structure.name
|
|
||||||
end
|
|
||||||
|
|
||||||
--- @class vim._gen_lsp.Property translated to @field
|
--- @class vim._gen_lsp.Property translated to @field
|
||||||
--- @field deprecated? string
|
--- @field deprecated? string
|
||||||
@ -319,15 +340,15 @@ function M.gen(opt)
|
|||||||
--- @field since? string
|
--- @field since? string
|
||||||
--- @field type { kind: string, name: string }
|
--- @field type { kind: string, name: string }
|
||||||
for _, field in ipairs(structure.properties or {}) do
|
for _, field in ipairs(structure.properties or {}) do
|
||||||
|
output[#output + 1] = '---' -- Insert a single newline between @fields (and after @class)
|
||||||
if field.documentation then
|
if field.documentation then
|
||||||
field.documentation = field.documentation:gsub('\n', '\n---')
|
output[#output + 1] = _process_documentation(field.documentation)
|
||||||
output[#output + 1] = '---' .. field.documentation
|
|
||||||
end
|
end
|
||||||
output[#output + 1] = '---@field '
|
output[#output + 1] = '---@field '
|
||||||
.. field.name
|
.. field.name
|
||||||
.. (field.optional and '?' or '')
|
.. (field.optional and '?' or '')
|
||||||
.. ' '
|
.. ' '
|
||||||
.. parse_type(field.type)
|
.. parse_type(field.type, field.name)
|
||||||
end
|
end
|
||||||
output[#output + 1] = ''
|
output[#output + 1] = ''
|
||||||
end
|
end
|
||||||
@ -342,8 +363,7 @@ function M.gen(opt)
|
|||||||
--- @field values { name: string, value: string, documentation?: string, since?: string }[]
|
--- @field values { name: string, value: string, documentation?: string, since?: string }[]
|
||||||
for _, enum in ipairs(protocol.enumerations) do
|
for _, enum in ipairs(protocol.enumerations) do
|
||||||
if enum.documentation then
|
if enum.documentation then
|
||||||
enum.documentation = enum.documentation:gsub('\n', '\n---')
|
output[#output + 1] = _process_documentation(enum.documentation)
|
||||||
output[#output + 1] = '---' .. enum.documentation
|
|
||||||
end
|
end
|
||||||
local enum_type = '---@alias lsp.' .. enum.name
|
local enum_type = '---@alias lsp.' .. enum.name
|
||||||
for _, value in ipairs(enum.values) do
|
for _, value in ipairs(enum.values) do
|
||||||
@ -366,18 +386,20 @@ function M.gen(opt)
|
|||||||
--- @field type vim._gen_lsp.Type
|
--- @field type vim._gen_lsp.Type
|
||||||
for _, alias in ipairs(protocol.typeAliases) do
|
for _, alias in ipairs(protocol.typeAliases) do
|
||||||
if alias.documentation then
|
if alias.documentation then
|
||||||
alias.documentation = alias.documentation:gsub('\n', '\n---')
|
output[#output + 1] = _process_documentation(alias.documentation)
|
||||||
output[#output + 1] = '---' .. alias.documentation
|
|
||||||
end
|
end
|
||||||
if alias.type.kind == 'or' then
|
if alias.type.kind == 'or' then
|
||||||
local alias_type = '---@alias lsp.' .. alias.name .. ' '
|
local alias_type = '---@alias lsp.' .. alias.name .. ' '
|
||||||
for _, item in ipairs(alias.type.items) do
|
for _, item in ipairs(alias.type.items) do
|
||||||
alias_type = alias_type .. parse_type(item) .. '|'
|
alias_type = alias_type .. parse_type(item, alias.name) .. '|'
|
||||||
end
|
end
|
||||||
alias_type = alias_type:sub(0, -2)
|
alias_type = alias_type:sub(0, -2)
|
||||||
output[#output + 1] = alias_type
|
output[#output + 1] = alias_type
|
||||||
else
|
else
|
||||||
output[#output + 1] = '---@alias lsp.' .. alias.name .. ' ' .. parse_type(alias.type)
|
output[#output + 1] = '---@alias lsp.'
|
||||||
|
.. alias.name
|
||||||
|
.. ' '
|
||||||
|
.. parse_type(alias.type, alias.name)
|
||||||
end
|
end
|
||||||
output[#output + 1] = ''
|
output[#output + 1] = ''
|
||||||
end
|
end
|
||||||
@ -387,7 +409,7 @@ function M.gen(opt)
|
|||||||
output[#output + 1] = line
|
output[#output + 1] = line
|
||||||
end
|
end
|
||||||
|
|
||||||
tofile(opt.output_file, table.concat(output, '\n'))
|
tofile(opt.output_file, table.concat(output, '\n') .. '\n')
|
||||||
end
|
end
|
||||||
|
|
||||||
---@type vim._gen_lsp.opt
|
---@type vim._gen_lsp.opt
|
||||||
|
Loading…
Reference in New Issue
Block a user