├── .gitmodules ├── README.md ├── autoload └── elixirls.vim └── plugin └── elixirls.vim /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "elixir-ls"] 2 | path = elixir-ls 3 | url = https://github.com/elixir-lsp/elixir-ls.git 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # What is it 2 | 3 | Vim and Neovim plugin that integrates [elixir-ls](https://github.com/JakeBecker/elixir-ls) with Vim through [ALE](https://github.com/w0rp/ale). It will download and compile [elixir-ls](https://github.com/JakeBecker/elixir-ls) upon installation. I also provided configuration instructions for integrating with [ALE](https://github.com/w0rp/ale) and a command for on-demand compilation. 4 | 5 | # How to install 6 | 7 | Use your favorite plugin manager. I prefer [vim-plug](https://github.com/junegunn/vim-plug): 8 | 9 | ``` 10 | Plug 'GrzegorzKozub/vim-elixirls', { 'do': ':ElixirLsCompileSync' } 11 | ``` 12 | 13 | Note that we're using [post-update hooks](https://github.com/junegunn/vim-plug#post-update-hooks) to automatically compile [elixir-ls](https://github.com/JakeBecker/elixir-ls) after this plugin has been installed or updated. 14 | 15 | # How to integrate with ALE 16 | 17 | At the minimum, you will need to tell [ALE](https://github.com/w0rp/ale) where the compiled [elixir-ls](https://github.com/JakeBecker/elixir-ls) sits and enable it as linter: 18 | 19 | ``` 20 | if has('nvim') 21 | let s:user_dir = stdpath('config') 22 | else 23 | let s:user_dir = has('win32') ? expand('~/vimfiles') : expand('~/.vim') 24 | endif 25 | 26 | let g:ale_elixir_elixir_ls_release = s:user_dir . '/plugins/vim-elixirls/elixir-ls/release' 27 | 28 | " https://github.com/JakeBecker/elixir-ls/issues/54 29 | let g:ale_elixir_elixir_ls_config = { 'elixirLS': { 'dialyzerEnabled': v:false } } 30 | 31 | let g:ale_linters = {} 32 | let g:ale_linters.elixir = [ 'credo', 'elixir-ls' ] 33 | ``` 34 | 35 | I'm using the following Vim key mappings for quick code navigation: 36 | 37 | ``` 38 | autocmd FileType elixir,eelixir nnoremap :ALEGoToDefinition 39 | autocmd FileType elixir,eelixir nnoremap :ALEFindReferences 40 | ``` 41 | 42 | You can use a version of elixir-ls other than the one that comes with this 43 | plugin by setting `g:vim_elixir_ls_elixir_ls_dir` to the path to your elixir-ls 44 | repo. Make sure to also set `g:ale_elixir_elixir_ls_release` as mentioned 45 | above. 46 | 47 | I'm using `mix format` to format my [elixir](https://elixir-lang.org/) code with this config: 48 | 49 | ``` 50 | let g:ale_fixers = {} 51 | let g:ale_fixers.elixir = [ 'mix_format' ] 52 | 53 | autocmd FileType elixir,eelixir nnoremap f :ALEFix 54 | ``` 55 | 56 | The `:ALEInfo` command is useful for figuring out why things are not working. 57 | 58 | # Compiling elixir-ls manually 59 | 60 | For [elixir-ls](https://github.com/JakeBecker/elixir-ls) to work, it needs to be compiled with the same [elixir](https://elixir-lang.org/) version as your code. Here's a handy command: 61 | 62 | ``` 63 | :ElixirLsCompile 64 | ``` 65 | 66 | -------------------------------------------------------------------------------- /autoload/elixirls.vim: -------------------------------------------------------------------------------- 1 | if exists('g:vim_elixirls_loaded') | finish | endif 2 | 3 | let s:vim = exists('*job_start') 4 | let s:neovim = exists('*jobstart') 5 | 6 | if !s:vim && !s:neovim 7 | echoerr 'The vim-elixirls plugin requires Vim 8 or Neovim' 8 | finish 9 | endif 10 | 11 | let s:repo = substitute(expand(':p:h:h') . '/elixir-ls', '\', '/', 'g') 12 | let s:wait_seconds = 120 13 | let s:timeout = 0 14 | if exists('s:job_id') | unlet s:job_id | endif 15 | 16 | function! elixirls#compile(wait) abort 17 | if exists('s:job_id') 18 | echomsg 'ElixirLS is already currently compiling in the background' 19 | return 20 | endif 21 | call s:start(a:wait) 22 | call s:handle_start(a:wait) 23 | endfunction 24 | 25 | if s:neovim 26 | 27 | function! s:start(wait) abort 28 | let s:job_id = jobstart(s:get_command(), s:get_options()) 29 | endfunction 30 | 31 | function! s:started() abort 32 | return s:job_id > 0 33 | endfunction 34 | 35 | function! s:wait() abort 36 | if jobwait([ s:job_id ], s:wait_seconds * 1000)[0] < 0 37 | let s:timeout = 1 38 | endif 39 | endfunction 40 | 41 | function! s:get_options() abort 42 | return { 'cwd': s:repo, 'on_exit': function('s:on_exit') } 43 | endfunction 44 | 45 | function! s:on_exit(job_id, data, event) abort 46 | call s:handle_exit(a:data) 47 | endfunction 48 | 49 | else 50 | 51 | function! s:start(wait) abort 52 | let s:job_id = job_start(s:get_command(), s:get_options()) 53 | endfunction 54 | 55 | function! s:started() abort 56 | return job_status(s:job_id) ==# 'run' 57 | endfunction 58 | 59 | function! s:wait() abort 60 | let l:wait_remaining = s:wait_seconds 61 | while l:wait_remaining > 0 && exists('s:job_id') && job_status(s:job_id) ==# 'run' 62 | let l:wait_remaining = l:wait_remaining - 1 63 | sleep 1000m 64 | endwhile 65 | if l:wait_remaining == 0 66 | let s:timeout = 1 67 | call job_stop(s:job_id) 68 | endif 69 | endfunction 70 | 71 | function! s:get_options() abort 72 | return { 'cwd': s:repo, 'exit_cb': function('s:on_exit') } 73 | endfunction 74 | 75 | function! s:on_exit(job, exit_status) abort 76 | call s:handle_exit(a:exit_status) 77 | endfunction 78 | 79 | endif 80 | 81 | function! s:handle_start(wait) abort 82 | redraw 83 | if s:started() 84 | echomsg 'ElixirLS compilation started' 85 | if a:wait | call s:wait() | endif 86 | else 87 | echoerr 'ElixirLS compilation failed to start' 88 | unlet s:job_id 89 | endif 90 | endfunction 91 | 92 | function! s:handle_exit(exit_code) abort 93 | redraw 94 | if s:timeout == 1 95 | let s:timeout = 0 96 | echoerr 'ElixirLS compilation timed out' 97 | else 98 | if a:exit_code == 0 99 | echomsg 'ElixirLS compiled successfully' 100 | else 101 | echoerr 'ElixirLS compilation failed. See logs in ' . s:repo 102 | endif 103 | endif 104 | unlet s:job_id 105 | endfunction 106 | 107 | function! s:get_command() abort 108 | let l:commands = [ 109 | \ 'mix deps.get > mix-deps.log 2>&1', 110 | \ 'mix compile > mix-compile.log 2>&1', 111 | \ 'mix elixir_ls.release -o release > mix-release.log 2>&1', 112 | \ 'rm *.log' 113 | \ ] 114 | if exists('g:vim_elixir_ls_elixir_ls_dir') 115 | let l:commands = [ 'cd ' . g:vim_elixir_ls_elixir_ls_dir ] + l:commands 116 | endif 117 | let l:script = join(commands, ' && ') 118 | return has('win32') ? 'cmd /c ' . l:script : [ '/bin/sh', '-c', l:script ] 119 | endfunction 120 | 121 | let g:vim_elixirls_loaded = 1 122 | 123 | -------------------------------------------------------------------------------- /plugin/elixirls.vim: -------------------------------------------------------------------------------- 1 | if exists('g:vim_elixirls_plugin_loaded') 2 | finish 3 | endif 4 | 5 | command! ElixirLsCompile call elixirls#compile(0) 6 | command! ElixirLsCompileSync call elixirls#compile(1) 7 | 8 | let g:vim_elixirls_plugin_loaded = 1 9 | 10 | --------------------------------------------------------------------------------