lspcontainers.nvim

repository·main·Indexed 43 days ago

https://github.com/lspcontainers/lspcontainers.nvim

A Neovim plugin that allows running language servers inside Docker or Podman containers, integrating with nvim-lspconfig. It supports a wide range of LSPs including clangd, gopls, pyright, and rust_analyzer, providing options for custom images, volume mounts, and network configuration.

Tokens
5.2K
Snippets
31
Records
32
Agent score
6%

What's inside lspcontainers.nvim

  1. Sync volume mounts with LSP root directory

    main

    When a language server requires the root_dir path to be synced with the Docker container's internal path, use the on_new_config hook in lspconfig. This ensures that whenever a new root directory is detected, the lspcontainers.command is re-generated with the correct root_dir context.

    local server = "lua_ls"
    require'lspconfig'[server].setup{
      on_new_config = function(new_config, new_root_dir)
        new_config.cmd = require'lspcontainers'.command(server, { root_dir = new_root_dir })
      end
    }
  2. Mount persistent Docker volumes or host paths

    main

    You can control how files are mounted into the container using the workdir and docker_volume options within lspcontainers.command.

    Mount a persistent Docker volume

    First, create a volume via CLI:

    docker create volume persistent_volume_projects

    Then, configure the LSP to use it:

    require'lspconfig'.omnisharp.setup {
      cmd = require'lspcontainers'.command(
          'omnisharp',
          {
              workdir = /projects,
              docker_volume = 'persistent_volume_projects',
          }
      ),
      -- ... other config
    }

    Mount a volume from the host

    To mount a path from your host machine, assign the host path to workdir:

    require'lspconfig'.omnisharp.setup {
      cmd = require'lspcontainers'.command(
          'omnisharp',
          {
              workdir = /home/[UserName]/projects
          }
      ),
      -- ... other config
    }
    require'lspconfig'.omnisharp.setup {
      capabilities = capabilities,
      before_init = before_init_process_id_nil,
      cmd = require'lspcontainers'.command(
          'omnisharp',
          {
              workdir = /projects,
              docker_volume = 'persistent_volume_projects',
          }
      ),
      on_new_config = on_new_config,
      on_attach = on_attach,
      root_dir = require'lspconfig/util'.root_pattern("*.sln", vim.fn.getcwd()),
    }
  3. Install lspcontainers.nvim

    main

    To use lspcontainers.nvim, you must first have the Docker Engine installed on your operating system. Then, install both nvim-lspconfig and lspcontainers.nvim using your preferred Neovim package manager.

    Note that lspcontainers.nvim expects the same language server names used by nvim-lspconfig.

    -- via packer
    use 'neovim/nvim-lspconfig'
    use 'lspcontainers/lspcontainers.nvim'
    " via vim-plug
    Plug 'neovim/nvim-lspconfig'
    Plug 'lspcontainers/lspcontainers.nvim'
  4. Configure additional languages via custom images

    main

    If a language is not in the default supported list, you can add it by providing a specific Docker image and a custom cmd function to lspcontainers.command. The cmd function allows you to define exactly how the container is run (e.g., adding --interactive or --rm flags).

    Note: lspcontainers.nvim does not modify LspConfig directly; you must pass these configurations into your standard lspconfig[server].setup calls.

    lspconfig.html.setup {
      on_attach = on_attach,
      capabilities = capabilities,
      cmd = lspcontainers.command('html', {
        image = "lspcontainers/html-language-server:1.4.0",
        cmd = function (runtime, volume, image)
          return {
            runtime,
            "container",
            "run",
            "--interactive",
            "--rm",
            "--volume",
            volume,
            image
          }
        end,
      }),
      root_dir = require'lspconfig/util'.root_pattern(".git", vim.fn.getcwd()),
    }
  5. Configure network access for LSPs

    main

    By default, lspcontainers.nvim runs containers with network=none for security. If an LSP requires network access (e.g., to fetch dependencies), set the network option to "bridge" in the lspcontainers.command options.

    cmd = lspcontainers.command('mylsp', {
      -- ...
      network = "bridge",
    }),
  6. Use Podman instead of Docker

    main

    If you are using Podman as your container runtime, specify container_runtime = "podman" in the options passed to lspcontainers.command.

    lspconfig.gopls.setup {
      on_attach = on_attach,
      capabilities = capabilities,
      cmd = lspcontainers.command('gopls', {
        container_runtime = "podman",
      }),
      root_dir = require'lspconfig/util'.root_pattern(".git", vim.fn.getcwd()),
    }
  7. Fix LSP exit issues by disabling Process ID detection

    main

    Some LSPs attempt to detect the client's process ID to shut down gracefully. Because containers do not share the host's process namespace by default, this detection can fail and cause the LSP to exit immediately.

    To fix this, you can disable process ID detection by setting params.processId = vim.NIL inside the before_init hook. This is required for several LSPs like bashls.

    require'lspconfig'.bashls.setup {
      before_init = function(params)
        params.processId = vim.NIL
      end,
      cmd = require'lspcontainers'.command('bashls'),
    }
  8. Configure omnisharp with lspcontainers

    main

    To use omnisharp via lspcontainers, set params.processId = vim.NIL in before_init and use require'lspcontainers'.command('omnisharp') for the cmd.

    require'lspconfig'.omnisharp.setup {
      before_init = function(params)
        params.processId = vim.NIL
      end,
      cmd = require'lspcontainers'.command('omnisharp'),
      root_dir = require'lspconfig/util'.root_pattern("*.sln", "*.csproj", vim.fn.getcwd()),
      ...
    }
  9. Configure yamlls with lspcontainers

    main

    To use yamlls via lspcontainers, set params.processId = vim.NIL in before_init and use require'lspcontainers'.command('yamlls') for the cmd.

    require'lspconfig'.yamlls.setup {
      before_init = function(params)
        params.processId = vim.NIL
      end,
      cmd = require'lspcontainers'.command('yamlls'),
      root_dir = require'lspconfig/util'.root_pattern(".git", vim.fn.getcwd()),
      ...
    }
  10. Configure pyright with lspcontainers

    main

    To use pyright via lspcontainers, set params.processId = vim.NIL in before_init and use require'lspcontainers'.command('pyright') for the cmd.

    require'lspconfig'.pyright.setup {
      before_init = function(params)
        params.processId = vim.NIL
      end,
      cmd = require'lspcontainers'.command('pyright'),
      root_dir = require'lspconfig/util'.root_pattern(".git", vim.fn.getcwd()),
      ...
    }