~whynothugo/dotfiles

50e71ecf374d62b2d7efc6576ade0f213d05bf2c — Hugo Osvaldo Barrera a month ago ed3237a
nvim: Redo LSP sandboxing

Add a wrapper function with all the ugly bits, and use a `network: bool`
flag to enable network.

The general goal is to make the API less tied to the sandboxing engine.
Ideally, some ideas from here can be re-used for lsp_containers.
1 files changed, 52 insertions(+), 19 deletions(-)

M home/.config/nvim/lua/lsp.lua
M home/.config/nvim/lua/lsp.lua => home/.config/nvim/lua/lsp.lua +52 -19
@@ 36,20 36,45 @@ local container_opts = {
}

-- Returns an `on_new_config` handler for an LSP.
local function on_new_config_brap(cmd, extra_args)
  -- This inner handler configures the LSP mounting only
  -- the project root inside of it.
  return function(new_config, new_root_dir)
    if type(extra_args) == "function" then
      extra_args = extra_args()
    elseif type(extra_args) == "nil" then
      extra_args = {}
    end
--
---@param name string
---@param opts table
---@return fun(name: string, opts: table): function
local function on_new_config_brap(name, opts)
  opts = opts or {}

  local cmd = opts.cmd
    or require("lspconfig.server_configurations." .. name).default_config.cmd

  local extra_args = {}
  -- TODO: extra_args might need to be a function sometimes.
  if opts.extra_args ~= nil then
    vim.list_extend(extra_args, opts.extra_args)
  end

    if type(cmd) == "string" then
      cmd = { cmd }
    end
  if opts.network == true then
    vim.list_extend(extra_args, {
      -- Actually share network.
      "--share-net",
      -- Required for DNS.
      "--ro-bind",
      "/etc/resolv.conf",
      "/etc/resolv.conf",
      -- Required for TLS / HTTPS.
      "--ro-bind",
      "/etc/ssl/certs/ca-certificates.crt",
      "/etc/ssl/certs/ca-certificates.crt",
    })
  end

  -- This inner handler configures the sandbox for the LSP. It mounts only the
  -- project root inside the sandbox filesystem (and paths required to actually
  -- execute the LSP).
  --
  ---@param new_config table
  ---@param new_root_dir string
  ---@return table
  return function(new_config, new_root_dir)
    new_config.cmd = vim.tbl_flatten({
      { "bwrap" },
      extra_args or {},


@@ 124,21 149,29 @@ local servers = {
  },
  bashls = {
    cmd = { "false" },
    on_new_config = on_new_config_brap("bash-language-server"),
    on_new_config = on_new_config_brap("bashls"),
  },
  terraformls = {
    cmd = { "false" },
    on_new_config = on_new_config_brap(
      require("lspconfig.server_configurations.terraformls").default_config.cmd
    ),
    on_new_config = on_new_config_brap("terraformls"),
  },
  dockerls = {
    cmd = lsp_containers.command("dockerls", container_opts),
  },
  gopls = {
    cmd = { "false" },
    -- TODO: also mount $GOPATH?
    on_new_config = on_new_config_brap("gopls", { "--share-net" }),
    on_new_config = on_new_config_brap("gopls", {
      network = true,
      extra_args = {
        -- Share GOPATH. This is a shared cache for modules.
        -- This is mounted in the same location as the host so code navigation
        -- into these can work too.
        "--bind",
        -- TODO: should host's read $GOPATH on both here:
        "/home/hugo/.cache/golang",
        "/home/hugo/.cache/golang",
      },
    }),
    settings = {
      gopls = {
        staticcheck = true,


@@ 167,7 200,7 @@ local servers = {
  },
  rnix = {
    cmd = { "false" },
    on_new_config = on_new_config_brap("rnix-lsp"),
    on_new_config = on_new_config_brap("rnix"),
  },
  -- TODO: "sorbet",  -- type checker for ruby
  -- TODO: "sourcekit",  -- swift