Cadence LSP in Neovim

Neovim has built in LSP support, and the Flow CLI tool has language-server capabilities built into it, so I’m trying to get it working in Neovim. This is in lieu of LSP support from the nvim-lspconfig plugin, which I am using for all of my language servers besides Cadence currently.

Preamble:

I am aware of the coc-cadence plugin. I do not use CoC in my nvim config. Instead I use:

  • nvim-cmp (for completion)
  • null-ls (for formatting)

So this is what I have in my config right now:

vim.api.nvim_create_autocmd("FileType", {
	pattern = "cadence",
	callback = function()
		vim.lsp.start({
			name = "cadence-language-server",
			cmd = { "flow", "cadence", "language-server" },
			root_dir = vim.fs.dirname(vim.fs.find({ "flow.json" }, { upward = true })[1]),
		})
	end,
})

But I get the following error upon nvim startup for a flow project:

Error executing vim.schedule lua callback: …w/Cellar/neovim/0.8.0/share/nvim/runtime/lua/vim/lsp.lua:1285: RPC[Error] code_name = InternalError, message = “invalid initializat
ion options”
stack traceback:
[C]: in function ‘assert’
…w/Cellar/neovim/0.8.0/share/nvim/runtime/lua/vim/lsp.lua:1285: in function ‘’
vim/_editor.lua: in function <vim/_editor.lua:0>

If anyone has luck getting the Cadence LSP that is bundled with the Flow CLI tool working with Neovim built in LSP, please do share here. I will be posting updates as I make progress.

Thanks all!

I have something like this:

local lspconfig = require("lspconfig")
local configs = require "lspconfig.configs"
configs["cadence_lsp"] = {
  default_config = {
    init_options = {
          configPath = "/Users/bluesign/flow/kitty-items/flow.json",
          numberOfAccounts = "1"
    },
    cmd = {'flow', 'cadence', 'language-server'},
    root_dir = lspconfig.util.root_pattern(".git"),
    filetypes = { "cdc","cadence" },
    on_attach = on_attach,
  },
}

init_options can be changed probably.

1 Like

@bluesign wonderful thank you for sharing your config :partying_face:!

The issue was not passing in init_options – I’m not used to manually setting up LSPs so was unsure if issue was coming from my set up, or the Cadence LSP interface available to nvim.

Here is my working config:

vim.api.nvim_create_autocmd("FileType", {
	pattern = "cadence",
	callback = function()
		local flow_project_dir = vim.fs.dirname(vim.fs.find({ "flow.json" }, { upward = true })[1])
		vim.lsp.start({
			name = "cadence-language-server",
			cmd = { "flow", "cadence", "language-server" },
			root_dir = flow_project_dir,
			init_options = {
				configPath = flow_project_dir .. "/flow.json",
				numberOfAccounts = "1",
			},
			on_attach = on_attach,
			capabilities = capabilities,
		})
	end,
})

Maybe you can try my implementation of init_options.configPath so you don’t have nvim hardcoded to use a single project.

Things to Figure Out Still

  • I like how you are importing from the lspconfig plugin. I tried out your implementation and couldn’t get LSP to attach. I will revisit this but for now I got the Cadence LSP running in Nvim which was my main goal.
  • I want to explore the rest of the init_options available. Feels odd hardcoding numberOfAccounts = "1" but not clear if it affects LSP usage in any way.

I think configPath doesn’t have much effect ( unless you want to deploy to the emulator in LSP )

Probably you may not need options, I just copied from vscode plugin ( I just use LSP part for syntax etc, for deploy I use flow-cli )

  • I like how you are importing from the lspconfig plugin. I tried out your implementation and couldn’t get LSP to attach. I will revisit this but for now I got the Cadence LSP running in Nvim which was my main goal.

Full config:

local on_attach = function(client, bufnr)
    vim.cmd("command! LspDef lua vim.lsp.buf.definition()")
    vim.cmd("command! LspFormatting lua vim.lsp.buf.formatting()")
    vim.cmd("command! LspCodeAction lua vim.lsp.buf.code_action()")
    vim.cmd("command! LspHover lua vim.lsp.buf.hover()")
    vim.cmd("command! LspRename lua vim.lsp.buf.rename()")
    vim.cmd("command! LspRefs lua vim.lsp.buf.references()")
    vim.cmd("command! LspTypeDef lua vim.lsp.buf.type_definition()")
    vim.cmd("command! LspImplementation lua vim.lsp.buf.implementation()")
    vim.cmd("command! LspDiagPrev lua vim.diagnostic.goto_prev()")
    vim.cmd("command! LspDiagNext lua vim.diagnostic.goto_next()")
    vim.cmd("command! LspDiagLine lua vim.diagnostic.open_float()")
    vim.cmd("command! LspSignatureHelp lua vim.lsp.buf.signature_help()")
    buf_map(bufnr, "n", "gd", ":LspDef<CR>")
    buf_map(bufnr, "n", "gr", ":LspRefs<CR>")
    buf_map(bufnr, "n", "gy", ":LspTypeDef<CR>")
    buf_map(bufnr, "n", "K", ":LspHover<CR>")
    buf_map(bufnr, "n", "[a", ":LspDiagPrev<CR>")
    buf_map(bufnr, "n", "]a", ":LspDiagNext<CR>")
    buf_map(bufnr, "n", "ga", ":lua vim.lsp.codelens.run {}<CR>")
    buf_map(bufnr, "n", "<Leader>a", ":LspDiagLine<CR>")
    buf_map(bufnr, "i", "<C-x><C-x>", "<cmd> LspSignatureHelp<CR>")
    
    vim.cmd("autocmd CursorHold,InsertLeave <buffer=%s> lua vim.lsp.codelens.refresh()")
    if client.resolved_capabilities.document_formatting then
        vim.cmd("autocmd BufWritePre <buffer> lua vim.lsp.buf.formatting_sync()")
    end
end

 local capabilities = require('cmp_nvim_lsp').update_capabilities(vim.lsp.protocol.make_client_capabilities())

local lspconfig = require("lspconfig")
local configs = require "lspconfig.configs"
configs["cadence_lsp"] = {
  default_config = {
    init_options = {
          configPath = "/Users/bluesign/flow/kitty-items/flow.json",
          numberOfAccounts = "1"
    },
    cmd = {'flow', 'cadence', 'language-server'},
    root_dir = lspconfig.util.root_pattern(".git"),
    filetypes = { "cdc","cadence" },
    on_attach = on_attach,
  },
}

lspconfig.cadence_lsp.setup {
     on_attach = function(client, bufnr)
        on_attach(client, bufnr)
    end, 
    capabilities = capabilities,
}