elixir.nvim
provides a nice experience for writing Elixir applications with Neovim.
Note: This plugin does not provide autocompletion, I recommend using nvim-cmp.
- ElixirLS installation and configuration (uses the Neovim built-in LSP client)
:Mix
command with autocomplete- vim-projectionist support
Requires 0.8.
{
"mhanberg/elixir.nvim",
ft = { "elixir", "eex", "heex", "surface" },
config = function()
local elixir = require("elixir")
elixir.setup {
settings = elixirls.settings {
dialyzerEnabled = false,
enableTestLenses = false,
},
log_level = vim.lsp.protocol.MessageType.Log,
message_level = vim.lsp.protocol.MessageType.Log,
on_attach = function(client, bufnr)
-- whatever keybinds you want, see below for more suggestions
vim.keymap.set("n", "<space>fp", ":ElixirFromPipe<cr>", { buffer = true, noremap = true })
vim.keymap.set("n", "<space>tp", ":ElixirToPipe<cr>", { buffer = true, noremap = true })
vim.keymap.set("v", "<space>em", ":ElixirExpandMacro<cr>", { buffer = true, noremap = true })
end,
}
end,
dependencies = {
"nvim-lua/plenary.nvim",
},
}
use({ "mhanberg/elixir.nvim", requires = { "nvim-lua/plenary.nvim" }})
require("elixir").setup()
While the plugin works with a minimal setup, it is much more useful if you add some personal configuration.
Note: Not specifying the repo
, branch
, or tag
options will default to the latest release.
local elixir = require("elixir")
elixir.setup({
-- specify a repository and branch
repo = "mhanberg/elixir-ls", -- defaults to elixir-lsp/elixir-ls
branch = "mh/all-workspace-symbols", -- defaults to nil, just checkouts out the default branch, mutually exclusive with the `tag` option
tag = "v0.13.0", -- defaults to nil, mutually exclusive with the `branch` option
-- alternatively, point to an existing elixir-ls installation (optional)
-- not currently supported by elixirls, but can be a table if you wish to pass other args `{"path/to/elixirls", "--foo"}`
cmd = "/usr/local/bin/elixir-ls.sh",
-- default settings, use the `settings` function to override settings
settings = elixir.settings({
dialyzerEnabled = true,
fetchDeps = false,
enableTestLenses = false,
suggestSpecs = false,
}),
on_attach = function(client, bufnr)
local map_opts = { buffer = true, noremap = true}
-- run the codelens under the cursor
vim.keymap.set("n", "<space>r", vim.lsp.codelens.run, map_opts)
-- remove the pipe operator
vim.keymap.set("n", "<space>fp", ":ElixirFromPipe<cr>", map_opts)
-- add the pipe operator
vim.keymap.set("n", "<space>tp", ":ElixirToPipe<cr>", map_opts)
vim.keymap.set("v", "<space>em", ":ElixirExpandMacro<cr>", map_opts)
-- bindings for standard LSP functions.
vim.keymap.set("n", "<space>df", "<cmd>lua vim.lsp.buf.format()<cr>", map_opts)
vim.keymap.set("n", "<space>gd", "<cmd>lua vim.diagnostic.open_float()<cr>", map_opts)
vim.keymap.set("n", "<space>dt", "<cmd>lua vim.lsp.buf.definition()<cr>", map_opts)
vim.keymap.set("n", "<space>K", "<cmd>lua vim.lsp.buf.hover()<cr>", map_opts)
vim.keymap.set("n", "<space>gD","<cmd>lua vim.lsp.buf.implementation()<cr>", map_opts)
vim.keymap.set("n", "<space>1gD","<cmd>lua vim.lsp.buf.type_definition()<cr>", map_opts)
-- keybinds for fzf-lsp.nvim: https://github.com/gfanto/fzf-lsp.nvim
-- you could also use telescope.nvim: https://github.com/nvim-telescope/telescope.nvim
-- there are also core vim.lsp functions that put the same data in the loclist
vim.keymap.set("n", "<space>gr", ":References<cr>", map_opts)
vim.keymap.set("n", "<space>g0", ":DocumentSymbols<cr>", map_opts)
vim.keymap.set("n", "<space>gW", ":WorkspaceSymbols<cr>", map_opts)
vim.keymap.set("n", "<leader>d", ":Diagnostics<cr>", map_opts)
-- keybinds for vim-vsnip: https://github.com/hrsh7th/vim-vsnip
vim.cmd([[imap <expr> <C-l> vsnip#available(1) ? '<Plug>(vsnip-expand-or-jump)' : '<C-l>']])
vim.cmd([[smap <expr> <C-l> vsnip#available(1) ? '<Plug>(vsnip-expand-or-jump)' : '<C-l>']])
-- update capabilities for nvim-cmp: https://github.com/hrsh7th/nvim-cmp
require("cmp_nvim_lsp").update_capabilities(capabilities)
end
})
When a compatible installation of ELixirLS is not found, you will be prompted to install it. The plugin will download the source code to the .elixir_ls
directory and compile it using the Elixir and OTP versions used by your current project.
Caveat: This assumes you are developing your project locally (outside of something like Docker) and they will be available.
Caveat: This currently downloads the language server into the .elixir_ls
directory in your repository, but it does install it into ~/.cache
and will re-use it when needed.
elixir.nvim
should be able to properly set the root directory for umbrella and non-umbrella apps. The nvim-lspconfig project's root detection doesn't properly account for umbrella projects.
ElixirLS provides a codelens to identify and run your tests. If you configure enableTestLenses = true
in the settings table, you will see the codelens as virtual text in your editor and can run them with vim.lsp.codelens.run()
.
The LS has the ability to convert the expression under the cursor form a normal function call to a "piped" function all (and vice versa).
:ElixirFromPipe
:ElixirToPipe
You can highlight a macro call in visual mode and "expand" the macro, opening a floating window with the results.
:'<,'>ElixirExpandMacro
You can restart the LS by using the restart command. This is useful if you think the LS has gotten into a weird state. It will send the restart command and then save and reload your current buffer to re-attach the client.
:ElixirRestart
You can see the logs for ElixirLS via the output panel. By default opens the buffer in a horizontal split window.
:ElixirOutputPanel
:lua require("elixir").open_output_panel()
:lua require("elixir").open_output_panel({ window = "split" })
:lua require("elixir").open_output_panel({ window = "vsplit" })
:lua require("elixir").open_output_panel({ window = "float" })
You can run any mix
command in your project, complete with... autocomplete!
:Mix compile --force
vim-projectionist definitions are provided for:
- Elixir files
- Phoenix Views
- Phoenix Controllers
- Phoenix Channels
- Wallaby/Hound Feature tests
TODO: make it work
TODO: gif