mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 19:38:20 +00:00
refactor(lsp): gen_lsp
- Simplify usage: - Instead of `nvim -l src/gen/gen_lsp.lua gen` now just run `./src/gen/gen_lsp.lua` - Removed `--methods` and `--capabilities` options. - Improved rendering code in various areas.
This commit is contained in:

committed by
Lewis Russell

parent
d7e0d46ffa
commit
2fcdeb0128
@@ -152,7 +152,7 @@ These dependencies are "vendored" (inlined), we must update the sources manually
|
|||||||
* `src/nvim/tui/terminfo_defs.h`: terminfo definitions
|
* `src/nvim/tui/terminfo_defs.h`: terminfo definitions
|
||||||
* Run `scripts/update_terminfo.sh` to update these definitions.
|
* Run `scripts/update_terminfo.sh` to update these definitions.
|
||||||
* `runtime/lua/vim/lsp/_meta/protocol.lua`: LSP specification
|
* `runtime/lua/vim/lsp/_meta/protocol.lua`: LSP specification
|
||||||
* Run `scripts/gen_lsp.lua` to update.
|
* Run `src/gen/gen_lsp.lua` to update.
|
||||||
* `runtime/lua/vim/_meta/lpeg.lua`: LPeg definitions.
|
* `runtime/lua/vim/_meta/lpeg.lua`: LPeg definitions.
|
||||||
* Refer to [`LuaCATS/lpeg`](https://github.com/LuaCATS/lpeg) for updates.
|
* Refer to [`LuaCATS/lpeg`](https://github.com/LuaCATS/lpeg) for updates.
|
||||||
* Update the git SHA revision from which the documentation was taken.
|
* Update the git SHA revision from which the documentation was taken.
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
--[[
|
--[[
|
||||||
THIS FILE IS GENERATED by scr/gen/gen_lsp.lua
|
THIS FILE IS GENERATED by src/gen/gen_lsp.lua
|
||||||
DO NOT EDIT MANUALLY
|
DO NOT EDIT MANUALLY
|
||||||
|
|
||||||
Based on LSP protocol 3.18
|
Based on LSP protocol 3.18
|
||||||
|
|
||||||
Regenerate:
|
Regenerate:
|
||||||
nvim -l scr/gen/gen_lsp.lua gen --version 3.18
|
nvim -l src/gen/gen_lsp.lua --version 3.18
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
---@meta
|
---@meta
|
||||||
|
530
src/gen/gen_lsp.lua
Normal file → Executable file
530
src/gen/gen_lsp.lua
Normal file → Executable file
@@ -1,29 +1,20 @@
|
|||||||
|
#!/usr/bin/env -S nvim -l
|
||||||
-- Generates lua-ls annotations for lsp.
|
-- Generates lua-ls annotations for lsp.
|
||||||
|
|
||||||
local USAGE = [[
|
local USAGE = [[
|
||||||
Generates lua-ls annotations for lsp.
|
Generates lua-ls annotations for lsp.
|
||||||
|
|
||||||
USAGE:
|
Also updates types in runtime/lua/vim/lsp/protocol.lua
|
||||||
nvim -l src/gen/gen_lsp.lua gen # by default, this will overwrite runtime/lua/vim/lsp/_meta/protocol.lua
|
|
||||||
nvim -l src/gen/gen_lsp.lua gen --version 3.18 --out runtime/lua/vim/lsp/_meta/protocol.lua
|
Usage:
|
||||||
nvim -l src/gen/gen_lsp.lua gen --version 3.18 --methods --capabilities
|
src/gen/gen_lsp.lua [options]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--version <version> LSP version to use (default: 3.18)
|
||||||
|
--out <out> Output file (default: runtime/lua/vim/lsp/_meta/protocol.lua)
|
||||||
|
--help Print this help message
|
||||||
]]
|
]]
|
||||||
|
|
||||||
local DEFAULT_LSP_VERSION = '3.18'
|
|
||||||
|
|
||||||
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
|
|
||||||
print(('Written to: %s'):format(fname))
|
|
||||||
f:write(text)
|
|
||||||
f:close()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- The LSP protocol JSON data (it's partial, non-exhaustive).
|
--- 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
|
--- https://raw.githubusercontent.com/microsoft/language-server-protocol/gh-pages/_specifications/lsp/3.18/metaModel/metaModel.schema.json
|
||||||
--- @class vim._gen_lsp.Protocol
|
--- @class vim._gen_lsp.Protocol
|
||||||
@@ -51,6 +42,66 @@ end
|
|||||||
--- @field partialResult? any
|
--- @field partialResult? any
|
||||||
--- @field result any
|
--- @field result any
|
||||||
|
|
||||||
|
--- @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
|
||||||
|
|
||||||
|
--- @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
|
||||||
|
|
||||||
|
--- @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 }
|
||||||
|
|
||||||
|
--- @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 }[]
|
||||||
|
|
||||||
|
--- @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
|
||||||
|
|
||||||
|
--- @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 fname string
|
||||||
|
--- @param text string
|
||||||
|
local function tofile(fname, text)
|
||||||
|
local f = assert(io.open(fname, 'w'), ('failed to open: %s'):format(fname))
|
||||||
|
f:write(text)
|
||||||
|
f:close()
|
||||||
|
print('Written to:', fname)
|
||||||
|
end
|
||||||
|
|
||||||
---@param opt vim._gen_lsp.opt
|
---@param opt vim._gen_lsp.opt
|
||||||
---@return vim._gen_lsp.Protocol
|
---@return vim._gen_lsp.Protocol
|
||||||
local function read_json(opt)
|
local function read_json(opt)
|
||||||
@@ -68,28 +119,24 @@ local function read_json(opt)
|
|||||||
return vim.json.decode(res.stdout)
|
return vim.json.decode(res.stdout)
|
||||||
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.
|
||||||
|
--- @param s string
|
||||||
|
--- @return string
|
||||||
local function to_luaname(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
|
||||||
|
|
||||||
|
--- @param a vim._gen_lsp.Notification
|
||||||
|
--- @param b vim._gen_lsp.Notification
|
||||||
|
--- @return boolean
|
||||||
|
local function compare_method(a, b)
|
||||||
|
return to_luaname(a.method) < to_luaname(b.method)
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param protocol vim._gen_lsp.Protocol
|
---@param protocol vim._gen_lsp.Protocol
|
||||||
---@param gen_methods boolean
|
local function write_to_vim_protocol(protocol)
|
||||||
---@param gen_capabilities boolean
|
local all = {} --- @type (vim._gen_lsp.Request|vim._gen_lsp.Notification)[]
|
||||||
local function write_to_protocol(protocol, gen_methods, gen_capabilities)
|
|
||||||
if not gen_methods and not gen_capabilities then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local indent = (' '):rep(2)
|
|
||||||
|
|
||||||
local function compare_method(a, b)
|
|
||||||
return to_luaname(a.method) < to_luaname(b.method)
|
|
||||||
end
|
|
||||||
|
|
||||||
---@type (vim._gen_lsp.Request|vim._gen_lsp.Notification)[]
|
|
||||||
local all = {}
|
|
||||||
vim.list_extend(all, protocol.notifications)
|
vim.list_extend(all, protocol.notifications)
|
||||||
vim.list_extend(all, protocol.requests)
|
vim.list_extend(all, protocol.requests)
|
||||||
|
|
||||||
@@ -99,7 +146,7 @@ local function write_to_protocol(protocol, gen_methods, gen_capabilities)
|
|||||||
|
|
||||||
local output = { '-- Generated by gen_lsp.lua, keep at end of file.' }
|
local output = { '-- Generated by gen_lsp.lua, keep at end of file.' }
|
||||||
|
|
||||||
if gen_methods then
|
do -- methods
|
||||||
for _, dir in ipairs({ 'clientToServer', 'serverToClient' }) do
|
for _, dir in ipairs({ 'clientToServer', 'serverToClient' }) do
|
||||||
local dir1 = dir:sub(1, 1):upper() .. dir:sub(2)
|
local dir1 = dir:sub(1, 1):upper() .. dir:sub(2)
|
||||||
local alias = ('vim.lsp.protocol.Method.%s'):format(dir1)
|
local alias = ('vim.lsp.protocol.Method.%s'):format(dir1)
|
||||||
@@ -141,16 +188,16 @@ local function write_to_protocol(protocol, gen_methods, gen_capabilities)
|
|||||||
if item.documentation then
|
if item.documentation then
|
||||||
local document = vim.split(item.documentation, '\n?\n', { trimempty = true })
|
local document = vim.split(item.documentation, '\n?\n', { trimempty = true })
|
||||||
for _, docstring in ipairs(document) do
|
for _, docstring in ipairs(document) do
|
||||||
output[#output + 1] = indent .. '--- ' .. docstring
|
output[#output + 1] = ' --- ' .. docstring
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
output[#output + 1] = ("%s%s = '%s',"):format(indent, to_luaname(item.method), item.method)
|
output[#output + 1] = (" %s = '%s',"):format(to_luaname(item.method), item.method)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
output[#output + 1] = '}'
|
output[#output + 1] = '}'
|
||||||
end
|
end
|
||||||
|
|
||||||
if gen_capabilities then
|
do -- capabilities
|
||||||
vim.list_extend(output, {
|
vim.list_extend(output, {
|
||||||
'',
|
'',
|
||||||
'-- stylua: ignore start',
|
'-- stylua: ignore start',
|
||||||
@@ -161,18 +208,9 @@ local function write_to_protocol(protocol, gen_methods, gen_capabilities)
|
|||||||
|
|
||||||
for _, item in ipairs(all) do
|
for _, item in ipairs(all) do
|
||||||
if item.serverCapability then
|
if item.serverCapability then
|
||||||
output[#output + 1] = ("%s['%s'] = { %s },"):format(
|
output[#output + 1] = (" ['%s'] = { %s },"):format(
|
||||||
indent,
|
|
||||||
item.method,
|
item.method,
|
||||||
table.concat(
|
"'" .. item.serverCapability:gsub('%.', "', '") .. "'"
|
||||||
vim
|
|
||||||
.iter(vim.split(item.serverCapability, '.', { plain = true }))
|
|
||||||
:map(function(segment)
|
|
||||||
return "'" .. segment .. "'"
|
|
||||||
end)
|
|
||||||
:totable(),
|
|
||||||
', '
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -197,28 +235,116 @@ local function write_to_protocol(protocol, gen_methods, gen_capabilities)
|
|||||||
vim.cmd.write()
|
vim.cmd.write()
|
||||||
end
|
end
|
||||||
|
|
||||||
---@class vim._gen_lsp.opt
|
--- @param doc string
|
||||||
---@field output_file string
|
local function process_documentation(doc)
|
||||||
---@field version string
|
doc = doc:gsub('\n', '\n---')
|
||||||
---@field methods boolean
|
-- Remove <200b> (zero-width space) unicode characters: e.g., `**/<200b>*`
|
||||||
---@field capabilities boolean
|
doc = doc:gsub('\226\128\139', '')
|
||||||
|
-- Escape annotations that are not recognized by lua-ls
|
||||||
|
doc = doc:gsub('%^---@sample', '---\\@sample')
|
||||||
|
return '---' .. doc
|
||||||
|
end
|
||||||
|
|
||||||
---@param opt vim._gen_lsp.opt
|
local simple_types = {
|
||||||
function M.gen(opt)
|
string = true,
|
||||||
--- @type vim._gen_lsp.Protocol
|
boolean = true,
|
||||||
local protocol = read_json(opt)
|
integer = true,
|
||||||
|
uinteger = true,
|
||||||
|
decimal = true,
|
||||||
|
}
|
||||||
|
|
||||||
write_to_protocol(protocol, opt.methods, opt.capabilities)
|
local anonymous_num = 0
|
||||||
|
|
||||||
|
--- @type string[]
|
||||||
|
local anonym_classes = {}
|
||||||
|
|
||||||
|
--- @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, prefix)
|
||||||
|
if type.kind == 'reference' or type.kind == 'base' then
|
||||||
|
if simple_types[type.name] then
|
||||||
|
return type.name
|
||||||
|
end
|
||||||
|
return 'lsp.' .. type.name
|
||||||
|
elseif type.kind == 'array' then
|
||||||
|
local parsed_items = parse_type(type.element, prefix)
|
||||||
|
if type.element.items and #type.element.items > 1 then
|
||||||
|
parsed_items = '(' .. parsed_items .. ')'
|
||||||
|
end
|
||||||
|
return parsed_items .. '[]'
|
||||||
|
elseif type.kind == 'or' then
|
||||||
|
local types = {} --- @type string[]
|
||||||
|
for _, item in ipairs(type.items) do
|
||||||
|
types[#types + 1] = parse_type(item, prefix)
|
||||||
|
end
|
||||||
|
return table.concat(types, '|')
|
||||||
|
elseif type.kind == 'stringLiteral' then
|
||||||
|
return '"' .. type.value .. '"'
|
||||||
|
elseif type.kind == 'map' then
|
||||||
|
local key = assert(type.key)
|
||||||
|
local value = type.value --[[ @as vim._gen_lsp.Type ]]
|
||||||
|
return ('table<%s, %s>'):format(parse_type(key, prefix), parse_type(value, prefix))
|
||||||
|
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 anonymous_classname = 'lsp._anonym' .. anonymous_num
|
||||||
|
if prefix then
|
||||||
|
anonymous_classname = anonymous_classname .. '.' .. prefix
|
||||||
|
end
|
||||||
|
|
||||||
|
local anonym = { '---@class ' .. anonymous_classname }
|
||||||
|
if anonymous_num > 1 then
|
||||||
|
table.insert(anonym, 1, '')
|
||||||
|
end
|
||||||
|
|
||||||
|
---@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
|
||||||
|
anonym[#anonym + 1] = process_documentation(field.documentation)
|
||||||
|
end
|
||||||
|
anonym[#anonym + 1] = ('---@field %s%s %s'):format(
|
||||||
|
field.name,
|
||||||
|
(field.optional and '?' or ''),
|
||||||
|
parse_type(field.type, prefix .. '.' .. field.name)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
for _, line in ipairs(anonym) do
|
||||||
|
if line then
|
||||||
|
anonym_classes[#anonym_classes + 1] = line
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return anonymous_classname
|
||||||
|
elseif type.kind == 'tuple' then
|
||||||
|
local types = {} --- @type string[]
|
||||||
|
for _, value in ipairs(type.items) do
|
||||||
|
types[#types + 1] = parse_type(value, prefix)
|
||||||
|
end
|
||||||
|
return '[' .. table.concat(types, ', ') .. ']'
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.print('WARNING: Unknown type ', type)
|
||||||
|
return ''
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param protocol vim._gen_lsp.Protocol
|
||||||
|
--- @param version string
|
||||||
|
--- @param output_file string
|
||||||
|
local function write_to_meta_protocol(protocol, version, output_file)
|
||||||
local output = {
|
local output = {
|
||||||
'--' .. '[[',
|
'--' .. '[[',
|
||||||
'THIS FILE IS GENERATED by scr/gen/gen_lsp.lua',
|
'THIS FILE IS GENERATED by src/gen/gen_lsp.lua',
|
||||||
'DO NOT EDIT MANUALLY',
|
'DO NOT EDIT MANUALLY',
|
||||||
'',
|
'',
|
||||||
'Based on LSP protocol ' .. opt.version,
|
'Based on LSP protocol ' .. version,
|
||||||
'',
|
'',
|
||||||
'Regenerate:',
|
'Regenerate:',
|
||||||
([=[nvim -l scr/gen/gen_lsp.lua gen --version %s]=]):format(DEFAULT_LSP_VERSION),
|
([=[nvim -l src/gen/gen_lsp.lua --version %s]=]):format(version),
|
||||||
'--' .. ']]',
|
'--' .. ']]',
|
||||||
'',
|
'',
|
||||||
'---@meta',
|
'---@meta',
|
||||||
@@ -232,150 +358,9 @@ function M.gen(opt)
|
|||||||
'',
|
'',
|
||||||
}
|
}
|
||||||
|
|
||||||
local anonymous_num = 0
|
|
||||||
|
|
||||||
---@type string[]
|
|
||||||
local anonym_classes = {}
|
|
||||||
|
|
||||||
local simple_types = {
|
|
||||||
'string',
|
|
||||||
'boolean',
|
|
||||||
'integer',
|
|
||||||
'uinteger',
|
|
||||||
'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
|
|
||||||
--- @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
|
|
||||||
---@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, prefix)
|
|
||||||
-- 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
|
|
||||||
local parsed_items = parse_type(type.element, prefix)
|
|
||||||
if type.element.items and #type.element.items > 1 then
|
|
||||||
parsed_items = '(' .. parsed_items .. ')'
|
|
||||||
end
|
|
||||||
return parsed_items .. '[]'
|
|
||||||
|
|
||||||
-- OrType
|
|
||||||
elseif type.kind == 'or' then
|
|
||||||
local val = ''
|
|
||||||
for _, item in ipairs(type.items) do
|
|
||||||
val = val .. parse_type(item, prefix) .. '|' --[[ @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
|
|
||||||
local key = assert(type.key)
|
|
||||||
local value = type.value --[[ @as vim._gen_lsp.Type ]]
|
|
||||||
return 'table<' .. parse_type(key, prefix) .. ', ' .. parse_type(value, prefix) .. '>'
|
|
||||||
|
|
||||||
-- 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 anonymous_classname = 'lsp._anonym' .. anonymous_num
|
|
||||||
if prefix then
|
|
||||||
anonymous_classname = anonymous_classname .. '.' .. prefix
|
|
||||||
end
|
|
||||||
local anonym = vim
|
|
||||||
.iter({
|
|
||||||
(anonymous_num > 1 and { '' } or {}),
|
|
||||||
{ '---@class ' .. anonymous_classname },
|
|
||||||
})
|
|
||||||
:flatten()
|
|
||||||
:totable()
|
|
||||||
|
|
||||||
--- @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
|
|
||||||
anonym[#anonym + 1] = '---'
|
|
||||||
if field.documentation then
|
|
||||||
anonym[#anonym + 1] = _process_documentation(field.documentation)
|
|
||||||
end
|
|
||||||
anonym[#anonym + 1] = '---@field '
|
|
||||||
.. field.name
|
|
||||||
.. (field.optional and '?' or '')
|
|
||||||
.. ' '
|
|
||||||
.. parse_type(field.type, prefix .. '.' .. field.name)
|
|
||||||
end
|
|
||||||
-- anonym[#anonym + 1] = ''
|
|
||||||
for _, line in ipairs(anonym) do
|
|
||||||
if line then
|
|
||||||
anonym_classes[#anonym_classes + 1] = line
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return anonymous_classname
|
|
||||||
|
|
||||||
-- TupleType
|
|
||||||
elseif type.kind == 'tuple' then
|
|
||||||
local tuple = '['
|
|
||||||
for _, value in ipairs(type.items) do
|
|
||||||
tuple = tuple .. parse_type(value, prefix) .. ', '
|
|
||||||
end
|
|
||||||
-- remove , at the end
|
|
||||||
tuple = tuple:sub(0, -3)
|
|
||||||
return tuple .. ']'
|
|
||||||
end
|
|
||||||
|
|
||||||
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
|
for _, structure in ipairs(protocol.structures) do
|
||||||
-- output[#output + 1] = ''
|
|
||||||
if structure.documentation then
|
if structure.documentation then
|
||||||
output[#output + 1] = _process_documentation(structure.documentation)
|
output[#output + 1] = process_documentation(structure.documentation)
|
||||||
end
|
end
|
||||||
local class_string = ('---@class lsp.%s'):format(structure.name)
|
local class_string = ('---@class lsp.%s'):format(structure.name)
|
||||||
if structure.extends or structure.mixins then
|
if structure.extends or structure.mixins then
|
||||||
@@ -390,126 +375,97 @@ function M.gen(opt)
|
|||||||
end
|
end
|
||||||
output[#output + 1] = class_string
|
output[#output + 1] = class_string
|
||||||
|
|
||||||
--- @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
|
for _, field in ipairs(structure.properties or {}) do
|
||||||
output[#output + 1] = '---' -- Insert a single newline between @fields (and after @class)
|
output[#output + 1] = '---' -- Insert a single newline between @fields (and after @class)
|
||||||
if field.documentation then
|
if field.documentation then
|
||||||
output[#output + 1] = _process_documentation(field.documentation)
|
output[#output + 1] = process_documentation(field.documentation)
|
||||||
end
|
end
|
||||||
output[#output + 1] = '---@field '
|
output[#output + 1] = ('---@field %s%s %s'):format(
|
||||||
.. field.name
|
field.name,
|
||||||
.. (field.optional and '?' or '')
|
(field.optional and '?' or ''),
|
||||||
.. ' '
|
parse_type(field.type, field.name)
|
||||||
.. parse_type(field.type, field.name)
|
)
|
||||||
end
|
end
|
||||||
output[#output + 1] = ''
|
output[#output + 1] = ''
|
||||||
end
|
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
|
for _, enum in ipairs(protocol.enumerations) do
|
||||||
if enum.documentation then
|
if enum.documentation then
|
||||||
output[#output + 1] = _process_documentation(enum.documentation)
|
output[#output + 1] = process_documentation(enum.documentation)
|
||||||
end
|
end
|
||||||
local enum_type = '---@alias lsp.' .. enum.name
|
output[#output + 1] = '---@alias lsp.' .. enum.name
|
||||||
for _, value in ipairs(enum.values) do
|
for _, value in ipairs(enum.values) do
|
||||||
enum_type = enum_type
|
local value1 = (type(value.value) == 'string' and ('"%s"'):format(value.value) or value.value)
|
||||||
.. '\n---| '
|
output[#output + 1] = ('---| %s # %s'):format(value1, value.name)
|
||||||
.. (type(value.value) == 'string' and '"' .. value.value .. '"' or value.value)
|
|
||||||
.. ' # '
|
|
||||||
.. value.name
|
|
||||||
end
|
end
|
||||||
output[#output + 1] = enum_type
|
|
||||||
output[#output + 1] = ''
|
output[#output + 1] = ''
|
||||||
end
|
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
|
for _, alias in ipairs(protocol.typeAliases) do
|
||||||
if alias.documentation then
|
if alias.documentation then
|
||||||
output[#output + 1] = _process_documentation(alias.documentation)
|
output[#output + 1] = process_documentation(alias.documentation)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local alias_type --- @type string
|
||||||
|
|
||||||
if alias.type.kind == 'or' then
|
if alias.type.kind == 'or' then
|
||||||
local alias_type = '---@alias lsp.' .. alias.name .. ' '
|
local alias_types = {} --- @type string[]
|
||||||
for _, item in ipairs(alias.type.items) do
|
for _, item in ipairs(alias.type.items) do
|
||||||
alias_type = alias_type .. parse_type(item, alias.name) .. '|'
|
alias_types[#alias_types + 1] = parse_type(item, alias.name)
|
||||||
end
|
end
|
||||||
alias_type = alias_type:sub(0, -2)
|
alias_type = table.concat(alias_types, '|')
|
||||||
output[#output + 1] = alias_type
|
|
||||||
else
|
else
|
||||||
output[#output + 1] = '---@alias lsp.'
|
alias_type = parse_type(alias.type, alias.name)
|
||||||
.. alias.name
|
|
||||||
.. ' '
|
|
||||||
.. parse_type(alias.type, alias.name)
|
|
||||||
end
|
end
|
||||||
|
output[#output + 1] = ('---@alias lsp.%s %s'):format(alias.name, alias_type)
|
||||||
output[#output + 1] = ''
|
output[#output + 1] = ''
|
||||||
end
|
end
|
||||||
|
|
||||||
-- anonymous classes
|
-- anonymous classes
|
||||||
for _, line in ipairs(anonym_classes) do
|
vim.list_extend(output, anonym_classes)
|
||||||
output[#output + 1] = line
|
|
||||||
end
|
|
||||||
|
|
||||||
tofile(opt.output_file, table.concat(output, '\n') .. '\n')
|
tofile(output_file, table.concat(output, '\n') .. '\n')
|
||||||
end
|
end
|
||||||
|
|
||||||
---@type vim._gen_lsp.opt
|
---@class vim._gen_lsp.opt
|
||||||
local opt = {
|
---@field output_file string
|
||||||
output_file = 'runtime/lua/vim/lsp/_meta/protocol.lua',
|
---@field version string
|
||||||
version = DEFAULT_LSP_VERSION,
|
|
||||||
methods = false,
|
|
||||||
capabilities = false,
|
|
||||||
}
|
|
||||||
|
|
||||||
local command = nil
|
--- @return vim._gen_lsp.opt
|
||||||
local i = 1
|
local function parse_args()
|
||||||
while i <= #_G.arg do
|
---@type vim._gen_lsp.opt
|
||||||
if _G.arg[i] == '--out' then
|
local opt = {
|
||||||
|
output_file = 'runtime/lua/vim/lsp/_meta/protocol.lua',
|
||||||
|
version = '3.18',
|
||||||
|
}
|
||||||
|
|
||||||
|
local i = 1
|
||||||
|
while i <= #_G.arg do
|
||||||
|
local cur_arg = _G.arg[i]
|
||||||
|
if cur_arg == '--out' then
|
||||||
opt.output_file = assert(_G.arg[i + 1], '--out <outfile> needed')
|
opt.output_file = assert(_G.arg[i + 1], '--out <outfile> needed')
|
||||||
i = i + 1
|
i = i + 1
|
||||||
elseif _G.arg[i] == '--version' then
|
elseif cur_arg == '--version' then
|
||||||
opt.version = assert(_G.arg[i + 1], '--version <version> needed')
|
opt.version = assert(_G.arg[i + 1], '--version <version> needed')
|
||||||
i = i + 1
|
i = i + 1
|
||||||
elseif _G.arg[i] == '--methods' then
|
elseif cur_arg == '--help' or cur_arg == '-h' then
|
||||||
opt.methods = true
|
print(USAGE)
|
||||||
elseif _G.arg[i] == '--capabilities' then
|
os.exit(0)
|
||||||
opt.capabilities = true
|
elseif vim.startswith(cur_arg, '-') then
|
||||||
elseif vim.startswith(_G.arg[i], '-') then
|
print('Unrecognized option:', cur_arg, '\n')
|
||||||
error('Unrecognized args: ' .. _G.arg[i])
|
os.exit(1)
|
||||||
else
|
|
||||||
if command then
|
|
||||||
error('More than one command was given: ' .. _G.arg[i])
|
|
||||||
else
|
|
||||||
command = _G.arg[i]
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
i = i + 1
|
i = i + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
return opt
|
||||||
end
|
end
|
||||||
|
|
||||||
if not command then
|
local function main()
|
||||||
print(USAGE)
|
local opt = parse_args()
|
||||||
elseif M[command] then
|
local protocol = read_json(opt)
|
||||||
M[command](opt) -- see M.gen()
|
write_to_vim_protocol(protocol)
|
||||||
else
|
write_to_meta_protocol(protocol, opt.version, opt.output_file)
|
||||||
error('Unknown command: ' .. command)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return M
|
main()
|
||||||
|
Reference in New Issue
Block a user