diff options
author | Jongwook Choi <wookayin@gmail.com> | 2023-12-11 02:25:17 -0500 |
---|---|---|
committer | Mathias Fußenegger <mfussenegger@users.noreply.github.com> | 2023-12-27 10:48:06 +0100 |
commit | 6c35fb421e888d0cbdfac07a5ff4579c9be7f0ec (patch) | |
tree | 03662f39cca7bcc11c7d1d8bb862dc9864828e87 /scripts/gen_lsp.lua | |
parent | 2f43af6423193eb52e9a6635034f8c79f40f1706 (diff) | |
download | rneovim-6c35fb421e888d0cbdfac07a5ff4579c9be7f0ec.tar.gz rneovim-6c35fb421e888d0cbdfac07a5ff4579c9be7f0ec.tar.bz2 rneovim-6c35fb421e888d0cbdfac07a5ff4579c9be7f0ec.zip |
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.
Diffstat (limited to 'scripts/gen_lsp.lua')
-rw-r--r-- | scripts/gen_lsp.lua | 98 |
1 files changed, 60 insertions, 38 deletions
diff --git a/scripts/gen_lsp.lua b/scripts/gen_lsp.lua index 943e88896b..0e7eb38cca 100644 --- a/scripts/gen_lsp.lua +++ b/scripts/gen_lsp.lua @@ -51,7 +51,7 @@ local function read_json(opt) end -- 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 return s:gsub('^%$', 'dollar'):gsub('/', '_') end @@ -95,7 +95,7 @@ local function gen_methods(protocol) ---@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) + return to_luaname(a.method) < to_luaname(b.method) end) for _, item in ipairs(all) do if item.method then @@ -105,7 +105,7 @@ local function gen_methods(protocol) output[#output + 1] = indent .. '--- ' .. docstring 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 output[#output + 1] = '}' @@ -193,6 +193,16 @@ function M.gen(opt) '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 --- @field kind string a common field for all Types. --- @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 ---@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 - local function parse_type(type) + local function parse_type(type, prefix) -- ReferenceType | BaseType if type.kind == 'reference' or type.kind == 'base' then if vim.tbl_contains(simple_types, type.name) then @@ -213,13 +225,13 @@ function M.gen(opt) -- ArrayType elseif type.kind == 'array' then - return parse_type(type.element) .. '[]' + return parse_type(type.element, prefix) .. '[]' -- OrType elseif type.kind == 'or' then local val = '' for _, item in ipairs(type.items) do - val = val .. parse_type(item) .. '|' --[[ @as string ]] + val = val .. parse_type(item, prefix) .. '|' --[[ @as string ]] end val = val:sub(0, -2) return val @@ -232,7 +244,7 @@ function M.gen(opt) elseif type.kind == 'map' then local key = assert(type.key) 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 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 -- https://github.com/LuaLS/lua-language-server/issues/2128 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. --- @field deprecated? string @@ -252,27 +271,29 @@ function M.gen(opt) ---@type vim._gen_lsp.StructureLiteral local structural_literal = assert(type.value) --[[ @as vim._gen_lsp.StructureLiteral ]] for _, field in ipairs(structural_literal.properties) do + anonym[#anonym + 1] = '---' if field.documentation then - field.documentation = field.documentation:gsub('\n', '\n---') - anonym[#anonym + 1] = '---' .. field.documentation + anonym[#anonym + 1] = _process_documentation(field.documentation) end anonym[#anonym + 1] = '---@field ' .. field.name .. (field.optional and '?' or '') .. ' ' - .. parse_type(field.type) + .. parse_type(field.type, prefix .. '.' .. field.name) end - anonym[#anonym + 1] = '' + -- anonym[#anonym + 1] = '' for _, line in ipairs(anonym) do - anonym_classes[#anonym_classes + 1] = line + if line then + anonym_classes[#anonym_classes + 1] = line + end end - return 'anonym' .. anonymous_num + return anonymous_classname -- TupleType elseif type.kind == 'tuple' then local tuple = '{ ' for i, value in ipairs(type.items) do - tuple = tuple .. '[' .. i .. ']: ' .. parse_type(value) .. ', ' + tuple = tuple .. '[' .. i .. ']: ' .. parse_type(value, prefix) .. ', ' end -- remove , at the end tuple = tuple:sub(0, -3) @@ -293,22 +314,22 @@ function M.gen(opt) --- @field proposed? boolean --- @field since? string for _, structure in ipairs(protocol.structures) do + -- output[#output + 1] = '' if structure.documentation then - structure.documentation = structure.documentation:gsub('\n', '\n---') - output[#output + 1] = '---' .. structure.documentation + output[#output + 1] = _process_documentation(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 + local class_string = ('---@class lsp.%s'):format(structure.name) + if structure.extends or structure.mixins then + local inherits_from = table.concat( + vim.list_extend( + vim.tbl_map(parse_type, structure.extends or {}), + vim.tbl_map(parse_type, structure.mixins or {}) + ), + ', ' + ) + class_string = class_string .. ': ' .. inherits_from end + output[#output + 1] = class_string --- @class vim._gen_lsp.Property translated to @field --- @field deprecated? string @@ -319,15 +340,15 @@ function M.gen(opt) --- @field since? string --- @field type { kind: string, name: string } for _, field in ipairs(structure.properties or {}) do + output[#output + 1] = '---' -- Insert a single newline between @fields (and after @class) if field.documentation then - field.documentation = field.documentation:gsub('\n', '\n---') - output[#output + 1] = '---' .. field.documentation + output[#output + 1] = _process_documentation(field.documentation) end output[#output + 1] = '---@field ' .. field.name .. (field.optional and '?' or '') .. ' ' - .. parse_type(field.type) + .. parse_type(field.type, field.name) end output[#output + 1] = '' end @@ -342,8 +363,7 @@ function M.gen(opt) --- @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---') - output[#output + 1] = '---' .. enum.documentation + output[#output + 1] = _process_documentation(enum.documentation) end local enum_type = '---@alias lsp.' .. enum.name for _, value in ipairs(enum.values) do @@ -366,18 +386,20 @@ function M.gen(opt) --- @field type vim._gen_lsp.Type for _, alias in ipairs(protocol.typeAliases) do if alias.documentation then - alias.documentation = alias.documentation:gsub('\n', '\n---') - output[#output + 1] = '---' .. alias.documentation + output[#output + 1] = _process_documentation(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) .. '|' + alias_type = alias_type .. parse_type(item, alias.name) .. '|' 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) + output[#output + 1] = '---@alias lsp.' + .. alias.name + .. ' ' + .. parse_type(alias.type, alias.name) end output[#output + 1] = '' end @@ -387,7 +409,7 @@ function M.gen(opt) output[#output + 1] = line end - tofile(opt.output_file, table.concat(output, '\n')) + tofile(opt.output_file, table.concat(output, '\n') .. '\n') end ---@type vim._gen_lsp.opt |