Skip to content

ci: generate annotations for Lua types#4306

Merged
justinmk merged 8 commits into
neovim:masterfrom
ofseed:ci-gen-annotations
Mar 13, 2026
Merged

ci: generate annotations for Lua types#4306
justinmk merged 8 commits into
neovim:masterfrom
ofseed:ci-gen-annotations

Conversation

@ofseed

@ofseed ofseed commented Feb 4, 2026

Copy link
Copy Markdown
Contributor

Automatically generate Lua types from the LSP server settings JSON schema
screenshot

Modified from neoconf.nvim

@igorlfs

igorlfs commented Feb 5, 2026

Copy link
Copy Markdown
Contributor

Hey, thanks for looking into this.

With #4010 I had a similar goal, although with a much more limited scope.

When this PR is finished, the changes, from a user's perspective, are:

  • Built-in configurations will now use custom types (e.g., instead of generic vim.lsp.Config, would use lspconfig.tsgo for tsgo, etc)
  • These custom types will be exposed, so they can also be used elsewhere (i.e., user's config)

Are these assumptions correct?

@ofseed

ofseed commented Feb 5, 2026

Copy link
Copy Markdown
Contributor Author
  • Built-in configurations will now use custom types (e.g., instead of generic vim.lsp.Config, would use lspconfig.tsgo for tsgo, etc)

Since the previous way to enable lspconfig followed the lspconfig.tsgo.setup pattern, neoconf was able to configure the type for keys like tsgo. This allowed users to avoid manual annotations once the generated types were loaded. However, the current vim.lsp.config chooses to pass the server name as a positional argument rather than a key, so this method might not be effective—it might still work via ---@overload, but I haven't tried that yet.

I don't intend to deprecate @type vim.lsp.Config, but rather to provide compatibility. My current preliminary plan is to provide a series of separate @class lspconfig.tsgo.settings, so that manual annotation is at least possible.

  • These custom types will be exposed, so they can also be used elsewhere (i.e., user's config)

Yes, this is a very important objective. In fact, neoconf itself doesn't need these type definitions; it generates them purely as a feature to make it convenient for users to use these types within their own configurations.

@ofseed ofseed force-pushed the ci-gen-annotations branch from cc526cd to 5917d35 Compare February 5, 2026 05:55
@ofseed

ofseed commented Feb 5, 2026

Copy link
Copy Markdown
Contributor Author

I just noticed an issue: since the JSON schemas are all JSON with comments rather than standard JSON, vim.json cannot be used here. Are there any plans to have vim.json support jsonc? Otherwise, a jsonc parser must be added here. cc @justinmk

@justinmk

justinmk commented Feb 5, 2026

Copy link
Copy Markdown
Member

Are there any plans to have vim.json support jsonc?

I'm favor of that but we don't have a tracking issue for it, nor in https://github.com/openresty/lua-cjson .

If it's not too horrible, this may even justify forking cjson if it won't be accepted upstream.

cc @skewb1k

@arkriny

arkriny commented Feb 5, 2026

Copy link
Copy Markdown
Contributor

Are there any plans to have vim.json support jsonc?

I think it's reasonable to have a flag for that.

I'm favor of that but we don't have a tracking issue for it, nor in https://github.com/openresty/lua-cjson .

If it's not too horrible, this may even justify forking cjson if it won't be accepted upstream.

We can take a similar approach to neovim/neovim#35574 and neovim/neovim#35424 by opening PRs to both upstream and neovim, and being okay with merging into neovim first. If upstream is not interested, we can certainly diverge. Additionally, I recall some discussions on Matrix regarding hard-forking due to API differences and other factors, so I don't think that's a problem.

@arkriny

arkriny commented Feb 6, 2026

Copy link
Copy Markdown
Contributor

I just noticed an issue: since the JSON schemas are all JSON with comments rather than standard JSON, vim.json cannot be used here.

While it's cool to support comments in vim.json and I'm working on the patch, I don't quite understand why its needed for JSON schemas? It seems that all schemas are valid JSONs, and the specification even introduces the $comment field, which is intended to be ignored semantically. Probably it wouldn't be necessary if the comment syntax was allowed.

local function readfile(path)
  local file = io.open(path, "r")
  if not file then
    return nil
  end
  local content = file:read("*a")
  file:close()
  return content
end

local dir = "./schemas"
local files = vim.fn.readdir(dir)
for _, file in ipairs(files) do
  local file_path = vim.fs.joinpath(dir, file)
  local content = readfile(file_path)
  vim.json.decode(content)
end

Running this in the root of https://github.com/folke/neoconf.nvim succeeds (introducing comment manually will cause it to fail).
I was thinking that in neoconf, jsonc is necessary to support comments in the user's config file. Am I missing something?

@ofseed

ofseed commented Feb 6, 2026

Copy link
Copy Markdown
Contributor Author

You are correct. I noticed that neoconf uses a JSONC decoder for JSON schemas, which led to my misunderstanding that JSON schemas could be JSONC; they should strictly be standard JSON.

The reason neoconf uses JSONC parsing here should because this wrapped function is also used to parse settings.json, which is allowed to be JSONC. Therefore, for this PR, using vim.json is sufficient.

Comment thread scripts/gen_types/util.lua Outdated
Comment thread scripts/gen_types/util.lua Outdated
@ofseed ofseed force-pushed the ci-gen-annotations branch 5 times, most recently from 1948f99 to 22ad3d9 Compare March 11, 2026 13:06
@ofseed ofseed marked this pull request as ready for review March 11, 2026 13:07
@ofseed ofseed requested a review from dundargoc as a code owner March 11, 2026 13:07
@ofseed

ofseed commented Mar 11, 2026

Copy link
Copy Markdown
Contributor Author

I have completed the essential refactoring; this PR is now in a usable state.

@ofseed ofseed force-pushed the ci-gen-annotations branch 4 times, most recently from 91e347e to a30c9d1 Compare March 11, 2026 16:22

@justinmk justinmk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lua/lspconfig/types/lsp.lua file is big and will keep growing. Does it avoid a perf issue if we split it into a bunch of files per-config?

Comment thread lsp/perlpls.lua Outdated
@@ -1,4 +1,5 @@
---@brief
---@schema https://raw.githubusercontent.com/FractalBoy/perl-language-server/master/client/package.json

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is @schema a LuaLS/emmylua feature? should we mention it in the readme?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just something I defined myself so that we can annotate the JSON schema while adding a server. I may need to mention it in the contributing guide or somewhere similar.

However, emmylua-analyzer-rust does have a @schemahttps://github.com/EmmyLuaLs/emmylua-analyzer-rust/pull/952)field that functions like @type, using a remote JSON schema as the @type. But it seems to support a limited version of JSON schema. I haven't tried it yet.

Comment thread README.md Outdated
Comment thread README.md
Comment thread .github/workflows/gen-annotations.yml Outdated
Comment thread scripts/gen_types/schemas.lua Outdated
Comment thread scripts/gen_types/schemas.lua Outdated
Comment thread scripts/gen_types/schemas.lua Outdated
Comment thread scripts/gen_types/util.lua Outdated
Comment thread scripts/gen_types/util.lua Outdated
Comment thread scripts/gen_types/annotations.lua Outdated
@ofseed

ofseed commented Mar 12, 2026

Copy link
Copy Markdown
Contributor Author

The lua/lspconfig/types/lsp.lua file is big and will keep growing. Does it avoid a perf issue if we split it into a bunch of files per-config?

I haven't noticed any performance issues during my own use, but the problem is that the default preloadFileSize field in the Lua LS setting is 500 KB, while the lsp.lua type file generated by this script is around 750 KB, causing the file to be ignored by default. It might be worth splitting it up or updating the preloadFileSize setting in lsp/lua_ls.lua.

I was just about to apply @type lspconfig.settings to the settings under lsp/, but then I noticed that some of the generated results seem to be invalid, maybe because the provided link is invalid. I probably need to double-check them before requesting a review again.

@ofseed ofseed force-pushed the ci-gen-annotations branch 3 times, most recently from 7f4598f to 6470e89 Compare March 13, 2026 12:03
Comment thread lua/lspconfig/types/lsp/yamlls.lua Outdated
Comment thread .github/workflows/gen-annotations.yml Outdated
@ofseed ofseed force-pushed the ci-gen-annotations branch 2 times, most recently from bb9a2be to 17005fa Compare March 13, 2026 13:21
@justinmk

Copy link
Copy Markdown
Member

the codespell CI should ignore types/ since we don't control the spelling there.
the other failing lints are presumably legitimate

@ofseed ofseed force-pushed the ci-gen-annotations branch from 0f7c62d to bbfc903 Compare March 13, 2026 13:52
Comment thread .styluaignore
@ofseed ofseed force-pushed the ci-gen-annotations branch 2 times, most recently from c52c718 to e480152 Compare March 13, 2026 14:29
@ofseed ofseed force-pushed the ci-gen-annotations branch from 3dd5244 to cfdc686 Compare March 13, 2026 14:46
@ofseed ofseed force-pushed the ci-gen-annotations branch from 768327b to 0b847c3 Compare March 13, 2026 14:47
@ofseed ofseed force-pushed the ci-gen-annotations branch from 94fddda to c5be612 Compare March 13, 2026 15:28
@ofseed ofseed force-pushed the ci-gen-annotations branch from c62f2c3 to 6b05a26 Compare March 13, 2026 15:38
Comment on lines +237 to +238
vim.fn.writefile(
vim.split(vim.json.encode(schema_json, { indent = ' ', sort_keys = true }), '\n', { plain = true }),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this reminds me we need neovim/neovim#31930 to make writefile() less annoying :)

---Regenerates all schema files under the local `schemas/` directory.
local function generate_all_schemas()
---@diagnostic disable-next-line: param-type-mismatch
vim.fn.delete(vim.fs.joinpath(vim.uv.cwd(), 'schemas'), 'rf')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just fyi, we have vim.fs.rm() now too

@justinmk justinmk merged commit 21b540f into neovim:master Mar 13, 2026
5 checks passed
@ofseed ofseed deleted the ci-gen-annotations branch March 13, 2026 16:02
@ofseed

ofseed commented Mar 14, 2026

Copy link
Copy Markdown
Contributor Author

I just noticed that I lost the Co-authored-by in the commit during the final rebase; thanks to @folke for providing the original version!

lervag added a commit to lervag/dotnvim that referenced this pull request Mar 15, 2026
lan1812783 added a commit to lan1812783/nvim that referenced this pull request Apr 1, 2026
Add Lua types from the LSP server settings, ref:
neovim/nvim-lspconfig#4306 (`gopls` seems to not have one).

Completion:
- Add `fuzzy` and change `noselect` to `noinsert` in `completeopt`.
- blink.cmp: do not automatically insert texts while cycling through the
  completion items.

Correctly remove `~` at the end of a buffer.
lan1812783 added a commit to lan1812783/nvim that referenced this pull request Apr 30, 2026
Add Lua types from the LSP server settings, ref:
neovim/nvim-lspconfig#4306 (`gopls` seems to not have one).

Completion:
- Add `fuzzy` and change `noselect` to `noinsert` in `completeopt`.
- blink.cmp: do not automatically insert texts while cycling through the
  completion items.

Correctly remove `~` at the end of a buffer.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants