Skip to content
BoostCookie edited this page Oct 2, 2023 · 22 revisions

LanguageClient-neovim

Vim and Neovim are able to use the Julia LanguageServer via LanguageClient-neovim with completion from nvim-completion-manager.

The following is a basic minimal config (vimrc for Vim; init.vim for Neovim) using vim-plug:

call g:plug#begin()
  Plug 'JuliaEditorSupport/julia-vim'
  Plug 'autozimu/LanguageClient-neovim', {'branch': 'next', 'do': 'bash install.sh'}
  Plug 'roxma/nvim-completion-manager'  " optional
call g:plug#end()

" julia
let g:default_julia_version = '1.0'

" language server
let g:LanguageClient_autoStart = 1
let g:LanguageClient_serverCommands = {
\   'julia': ['julia', '--startup-file=no', '--history-file=no', '-e', '
\       using LanguageServer;
\       using Pkg;
\       import StaticLint;
\       import SymbolServer;
\       env_path = dirname(Pkg.Types.Context().env.project_file);
\       
\       server = LanguageServer.LanguageServerInstance(stdin, stdout, env_path, "");
\       server.runlinter = true;
\       run(server);
\   ']
\ }

nnoremap <silent> K :call LanguageClient_textDocument_hover()<CR>
nnoremap <silent> gd :call LanguageClient_textDocument_definition()<CR>
nnoremap <silent> <F2> :call LanguageClient_textDocument_rename()<CR>

Note:

  1. The LanguageServer, SymbolServer and StaticLint packages must be installed in Julia (1.x), i.e.

    julia> using Pkg
    julia> Pkg.add("LanguageServer")
    julia> Pkg.add("SymbolServer")
    julia> Pkg.add("StaticLint")
  2. If Julia (0.6 or greater) is not present in the PATH environment, either add the julia binary folder to PATH or directly reference the julia binary in g:LanguageClient_serverCommands, e.g. for macOS:

    let g:LanguageClient_serverCommands = {
    \   'julia': ['/Applications/Julia-0.6.app/Contents/Resources/julia/bin/julia', ...
  3. See vim-plug for more details on installing/managing packages in Vim/Neovim

SpaceVim

SpaceVim have a layer to use LanguageServer.jl, the setup is automatic once you installed the Julia layer.

Neovim Built In LSP

an overview of state of built-in LSP and friends plug-ins: https://crispgm.com/page/neovim-is-overpowering.html

Using Deoplete

Check out this thread on discourse: https://discourse.julialang.org/t/neovim-languageserver-jl/37286/7 OR this blog post. This provides examples of using neovim's built in language server protocol using deoplete with deoplete-lsp.

Using nvim-cmp and nvim-lspconfig

See minimal example here:

-- using packer
-- ...

use({ 
  "hrsh7th/nvim-cmp",
  requires = { { "hrsh7th/cmp-nvim-lsp" } },
  config = function()
    cmp.setup({

      completion = {
        completeopt = "menu,menuone,noselect",
      },

      -- You must set mapping.
      mapping = {
        ["<C-p>"] = cmp.mapping.select_prev_item(),
        ["<C-n>"] = cmp.mapping.select_next_item(),
        ["<C-d>"] = cmp.mapping.scroll_docs(-4),
        ["<C-f>"] = cmp.mapping.scroll_docs(4),
        ["<C-Space>"] = cmp.mapping.complete(),
        ["<C-e>"] = cmp.mapping.close(),
      },

      -- You should specify your *installed* sources.
      sources = {
        { name = "nvim_lsp" },
      },
    })

  end,
})

use({
  "neovim/nvim-lspconfig",
  config = function()
    local function create_capabilities()
      local capabilities = vim.lsp.protocol.make_client_capabilities()
      capabilities.textDocument.completion.completionItem.snippetSupport = true
      capabilities.textDocument.completion.completionItem.preselectSupport = true
      capabilities.textDocument.completion.completionItem.tagSupport = { valueSet = { 1 } }
      capabilities.textDocument.completion.completionItem.deprecatedSupport = true
      capabilities.textDocument.completion.completionItem.insertReplaceSupport = true
      capabilities.textDocument.completion.completionItem.labelDetailsSupport = true
      capabilities.textDocument.completion.completionItem.commitCharactersSupport = true
      capabilities.textDocument.completion.completionItem.resolveSupport = {
        properties = { "documentation", "detail", "additionalTextEdits" },
      }
      capabilities.textDocument.completion.completionItem.documentationFormat = { "markdown" }
      capabilities.textDocument.codeAction = {
        dynamicRegistration = true,
        codeActionLiteralSupport = {
          codeActionKind = {
            valueSet = (function()
              local res = vim.tbl_values(vim.lsp.protocol.CodeActionKind)
              table.sort(res)
              return res
            end)(),
          },
        },
      }
      return capabilities
    end
    
    -- disable virtual text (recommended for julia)
    vim.lsp.handlers["textDocument/publishDiagnostics"] = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
      virtual_text = false,
      underline = false,
      signs = true,
      update_in_insert = false,
    })
    
    local on_attach = function(client, bufnr)
      vim.api.nvim_buf_set_option(bufnr, "omnifunc", "v:lua.vim.lsp.omnifunc")
    end
    
    local lspconfig = require("lspconfig")
    
    local function lsp_setup(name, config)
      lspconfig[name].setup(config)
    end
    
    lsp_setup("julials", {
      on_attach = on_attach,
      capabilities = create_capabilities(),
    })

  end,
})

-- ...

For a full example, see the following files:

Using completion-nvim (deprecated)

You can also see examples of using neovim, nvim-lsp, completion-nvim and diagnostic-nvim here:

https://github.com/kdheepak/dotfiles/blob/47a38e20ef4bef7a189927646eee3c91f911ffd7/vimrc

Here's the relevant pieces:

  1. Install the plugins
Plug 'nvim-lua/completion-nvim'                                    | " better neovim built in lsp completion
  1. Initialize
autocmd BufEnter * lua require'completion'.on_attach()

lua << EOF
    local nvim_lsp = require'nvim_lsp'
    local on_attach_vim = function()
        require'diagnostic'.on_attach()
    end
    nvim_lsp.julials.setup({on_attach=on_attach_vim})
EOF
  1. Configure
let g:diagnostic_auto_popup_while_jump = 0
let g:diagnostic_enable_virtual_text = 0
let g:diagnostic_enable_underline = 0
let g:completion_timer_cycle = 200 "default value is 80