aboutsummaryrefslogtreecommitdiffstats
path: root/neovim/.config/nvim/lua/plugins/lsp.lua
blob: 6f365a096715d4eb5a91db5bad79da8c9345b16f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
return {
  "mason-org/mason-lspconfig.nvim",
  dependencies = {
    { "mason-org/mason.nvim", opts = {} },
    "neovim/nvim-lspconfig",
    "saghen/blink.cmp",
  },
  opts = {
    ensure_installed = {
      "pyright",
      "lua_ls",
      "bashls",
      "terraformls",
      "yamlls",
      "ts_ls",
      "cssls",
      "html",
      "helm_ls",
    },
    -- default true: auto-calls vim.lsp.enable() for every Mason-installed
    -- server as it finishes installing.
  },
  config = function(_, opts)
    -- helm_ls's default config only attaches to filetype "helm" /
    -- "yaml.helm-values" (not plain "yaml"), so without this,
    -- templates/*.yaml only gets yamlls — which flags Helm's Go template
    -- syntax ({{ .Values.x }}) as invalid YAML. values.yaml gets the
    -- composite filetype instead, which both yamlls and helm_ls match, so
    -- it keeps YAML validation *and* gets helm_ls's values-schema support.
    vim.filetype.add({
      pattern = {
        [".*/templates/.*%.ya?ml"] = "helm",
        [".*/templates/.*%.tpl"] = "helm",
        [".*/values.*%.ya?ml"] = "yaml.helm-values",
      },
    })

    -- Merge blink.cmp's LSP capabilities into every server's default config
    -- (Mason-managed or not) before any server gets enabled.
    vim.lsp.config("*", {
      capabilities = require("blink.cmp").get_lsp_capabilities(),
    })

    -- yamlls only completes/validates when a schema is associated with the
    -- file, and plain k8s manifests don't match anything by filename. So we
    -- detect manifests by content (top-level apiVersion + kind) and add each
    -- one to yamlls's built-in "kubernetes" schema. CRDs (ArgoCD, Traefik,
    -- cert-manager, ...) are then resolved from apiVersion/kind by yamlls's
    -- CRD store, which is enabled by default.
    vim.lsp.config("yamlls", {
      settings = { yaml = { schemas = { kubernetes = {} } } },
    })

    local function is_k8s_manifest(bufnr)
      local has_api, has_kind = false, false
      for _, line in ipairs(vim.api.nvim_buf_get_lines(bufnr, 0, 50, false)) do
        has_api = has_api or line:match("^apiVersion:") ~= nil
        has_kind = has_kind or line:match("^kind:") ~= nil
      end
      return has_api and has_kind
    end

    local function attach_k8s_schema(client, bufnr)
      local path = vim.api.nvim_buf_get_name(bufnr)
      if path == "" or not is_k8s_manifest(bufnr) then
        return
      end
      local k8s = client.settings.yaml.schemas.kubernetes
      if vim.tbl_contains(k8s, path) then
        return
      end
      table.insert(k8s, path)
      client:notify("workspace/didChangeConfiguration", { settings = client.settings })
    end

    local group = vim.api.nvim_create_augroup("yamlls_kubernetes", { clear = true })
    vim.api.nvim_create_autocmd("LspAttach", {
      group = group,
      callback = function(args)
        local client = vim.lsp.get_client_by_id(args.data.client_id)
        if client and client.name == "yamlls" then
          attach_k8s_schema(client, args.buf)
        end
      end,
    })
    -- Also re-check on save, so a new file picks up the schema once
    -- apiVersion/kind have been written.
    vim.api.nvim_create_autocmd("BufWritePost", {
      group = group,
      callback = function(args)
        for _, client in ipairs(vim.lsp.get_clients({ bufnr = args.buf, name = "yamlls" })) do
          attach_k8s_schema(client, args.buf)
        end
      end,
    })

    require("mason-lspconfig").setup(opts)

    -- clangd ships with Xcode Command Line Tools already, so it's not
    -- Mason-managed — nvim-lspconfig provides its default config, we just
    -- need to turn it on.
    vim.lsp.enable("clangd")
  end,
}