Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 25 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Provide a simple method for running language servers in Docker containers using

## Installation

1. Install latest [Docker Engine](https://docs.docker.com/engine/install/) for your operating system
1. Install latest [Docker Engine](https://docs.docker.com/engine/install/) or [Podman](https://podman.io/) for your operating system

2. Install `lspconfig` and `lspcontainers` via package manager

Expand All @@ -28,6 +28,8 @@ Provide a simple method for running language servers in Docker containers using
Plug 'lspcontainers/lspcontainers.nvim'
```

- [configure your runtime](#podman-support) if you are using something other than docker

3. Setup the language of your choice from [Supported LSPs](#supported-lsps)

## Advanced Configuration
Expand All @@ -43,19 +45,31 @@ 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)
image = "lspcontainers/html-language-server:1.4.0",
cmd = function (workdir, image, network, docker_volume)
if vim.loop.os_uname().sysname == "Windows_NT" then
workdir = Dos2UnixSafePath(workdir)
end

local mnt_volume
if docker_volume ~= nil then
mnt_volume ="--volume="..docker_volume..":"..workdir..":z"
else
mnt_volume = "--volume="..workdir..":"..workdir..":z"
end

return {
runtime,
LspContainersConfig.runtime,
"container",
"run",
"--interactive",
"--rm",
"--volume",
volume,
"--network="..network,
"--workdir="..workdir,
mnt_volume,
image
}
end,
end
}),
root_dir = lspconfig.util.root_pattern(".git", vim.fn.getcwd()),
}
Expand All @@ -81,6 +95,7 @@ require'lspconfig'[server].setup{
You can either mount a path on host or a docker volume

#### Mount Persistent volume

You can [created a volume](https://docs.docker.com/engine/reference/commandline/volume_create/) (docker_volume) and mount it at path (workdir).

```bash
Expand Down Expand Up @@ -126,17 +141,11 @@ require'lspconfig'.omnisharp.setup {

### Podman Support

If you are using podman instead of docker it is sufficient to just specify "podman" as `container_runtime`:
If you are using podman or any other docker API compatible runtime the default `docker` runtime can
be overwritten during setup:

```lua
lspconfig.gopls.setup {
on_attach = on_attach,
capabilities = capabilities,
cmd = lspcontainers.command('gopls', {
container_runtime = "podman",
}),
root_dir = lspconfig.util.root_pattern(".git", vim.fn.getcwd()),
}
require'lspcontainers'.setup({ runtime = "podman" })
```

### Network support
Expand Down
50 changes: 30 additions & 20 deletions lua/lspcontainers/init.lua
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
Config = {
ensure_installed = {}
LspContainersConfig = {
ensure_installed = {},
runtime = "docker",
network = "bridge"
}

local supported_languages = {
bashls = { image = "docker.io/lspcontainers/bash-language-server" },
clangd = { image = "docker.io/lspcontainers/clangd-language-server" },
dockerls = { image = "docker.io/lspcontainers/docker-language-server" },
gopls = {
cmd_builder = function (runtime, workdir, image, network)
cmd_builder = function (workdir, image, network)
local volume = workdir..":"..workdir..":z"
local env = vim.api.nvim_eval('environ()')
local gopath = env.GOPATH or env.HOME.."/go"
Expand All @@ -24,14 +26,14 @@ local supported_languages = {

local user = user_id..":"..group_id

if runtime == "docker" then
if LspContainersConfig.runtime == "docker" then
network = "bridge"
elseif runtime == "podman" then
elseif LspContainersConfig.runtime == "podman" then
network = "slirp4netns"
end

return {
runtime,
LspContainersConfig.runtime,
"container",
"run",
"--env",
Expand Down Expand Up @@ -69,7 +71,7 @@ local supported_languages = {
}

-- default command to run the lsp container
local default_cmd = function (runtime, workdir, image, network, docker_volume)
local default_cmd = function (workdir, image, wantNetwork, docker_volume)
if vim.loop.os_uname().sysname == "Windows_NT" then
workdir = Dos2UnixSafePath(workdir)
end
Expand All @@ -81,13 +83,18 @@ local default_cmd = function (runtime, workdir, image, network, docker_volume)
mnt_volume = "--volume="..workdir..":"..workdir..":z"
end

local n = "none"
if wantNetwork then
n = LspContainersConfig.network
end

return {
runtime,
LspContainersConfig.runtime,
"container",
"run",
"--interactive",
"--rm",
"--network="..network,
"--network="..n,
"--workdir="..workdir,
mnt_volume,
image
Expand All @@ -97,10 +104,9 @@ end
local function command(server, user_opts)
-- Start out with the default values:
local opts = {
container_runtime = "docker",
root_dir = vim.fn.getcwd(),
cmd_builder = default_cmd,
network = "none",
wantNetwork = false,
docker_volume = nil,
}

Expand All @@ -119,7 +125,7 @@ local function command(server, user_opts)
return 1
end

return opts.cmd_builder(opts.container_runtime, opts.root_dir, opts.image, opts.network, opts.docker_volume)
return opts.cmd_builder(opts.root_dir, opts.image, opts.wantNetwork, opts.docker_volume)
end

Dos2UnixSafePath = function(workdir)
Expand All @@ -140,16 +146,15 @@ local function on_event(_, data, event)
end
end

local function images_pull(runtime)
local function images_pull()
local jobs = {}
runtime = runtime or "docker"

for idx, server_name in ipairs(Config.ensure_installed) do
for idx, server_name in ipairs(LspContainersConfig.ensure_installed) do
local server = supported_languages[server_name]

local job_id =
vim.fn.jobstart(
runtime.." image pull "..server['image'],
LspContainersConfig.runtime.." image pull "..server['image'],
{
on_stderr = on_event,
on_stdout = on_event,
Expand All @@ -165,14 +170,13 @@ local function images_pull(runtime)
print("lspcontainers: Language servers successfully pulled")
end

local function images_remove(runtime)
local function images_remove()
local jobs = {}
runtime = runtime or "docker"

for _, v in pairs(supported_languages) do
local job =
vim.fn.jobstart(
runtime.." image rm --force "..v['image']..":latest",
LspContainersConfig.runtime.." image rm --force "..v['image']..":latest",
{
on_stderr = on_event,
on_stdout = on_event,
Expand All @@ -193,7 +197,13 @@ vim.api.nvim_create_user_command("LspImagesRemove", images_remove, {})

local function setup(options)
if options['ensure_installed'] then
Config.ensure_installed = options['ensure_installed']
LspContainersConfig.ensure_installed = options['ensure_installed']
end
if options['runtime'] then
LspContainersConfig.runtime = options['runtime']
end
if options['network'] then
LspContainersConfig.network = options['network']
end
end

Expand Down