elixir-tools.nvim
elixir-tools.nvim copied to clipboard
Neovim plugin for Elixir
elixir.nvim
elixir.nvim provides a nice experience for writing Elixir applications with Neovim.
Note: This plugin does not provide autocompletion, I recommend using nvim-cmp.
Features
- ElixirLS installation and configuration (uses the Neovim built-in LSP client)
:Mixcommand with autocomplete- vim-projectionist support
Install
Requires 0.7+.
use({ "mhanberg/elixir.nvim", requires = { "neovim/nvim-lspconfig", "nvim-lua/plenary.nvim" }})
Getting Started
Minimal Setup
require("elixir").setup()
Advanced Setup
While the plugin works with a minimal setup, it is much more useful if you add some personal configuration.
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.9.0", -- defaults to nil, mutually exclusive with the `branch` option
-- 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)
-- standard lsp keybinds
vim.keymap.set("n", "df", "<cmd>lua vim.lsp.buf.formatting_seq_sync()<cr>", map_opts)
vim.keymap.set("n", "gd", "<cmd>lua vim.diagnostic.open_float()<cr>", map_opts)
vim.keymap.set("n", "dt", "<cmd>lua vim.lsp.buf.definition()<cr>", map_opts)
vim.keymap.set("n", "K", "<cmd>lua vim.lsp.buf.hover()<cr>", map_opts)
vim.keymap.set("n", "gD","<cmd>lua vim.lsp.buf.implementation()<cr>", map_opts)
vim.keymap.set("n", "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", "gr", ":References<cr>", map_opts)
vim.keymap.set("n", "g0", ":DocumentSymbols<cr>", map_opts)
vim.keymap.set("n", "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
})
Features
Language Server
Automatic ElixirLS Installation
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.

Root Path Detection
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.
Run Tests
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().

Manipulate Pipes
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

Expand Macro
You can highlight a macro call in visual mode and "expand" the macro, opening a floating window with the results.
:'<,'>ElixirExpandMacro

Restart
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
OutputPanel
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" })
Mix
You can run any mix command in your project, complete with... autocomplete!
:Mix compile --force

Projectionist
vim-projectionist definitions are provided for:
- Elixir files
- Phoenix Views
- Phoenix Controllers
- Phoenix Channels
- Wallaby/Hound Feature tests
Debugger
TODO: make it work
TODO: gif