337 lines
15 KiB
EmacsLisp
337 lines
15 KiB
EmacsLisp
|
|
;;; lsp-kubernetes-helm.el --- LSP YAML server integration -*- lexical-binding: t; -*-
|
||
|
|
|
||
|
|
;; Copyright (C) 2024 Aaron Gonzales
|
||
|
|
;; Copyright (C) 2024-2026 emacs-lsp maintainers
|
||
|
|
|
||
|
|
;; Author: Aaron Gonzales <aarongonzales1@gmail.com>
|
||
|
|
;; Keywords: lsp, kubernetes, helm, yaml
|
||
|
|
|
||
|
|
;; This program is free software; you can redistribute it and/or modify
|
||
|
|
;; it under the terms of the GNU General Public License as published by
|
||
|
|
;; the Free Software Foundation, either version 3 of the License, or
|
||
|
|
;; (at your option) any later version.
|
||
|
|
|
||
|
|
;; This program is distributed in the hope that it will be useful,
|
||
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
|
;; GNU General Public License for more details.
|
||
|
|
|
||
|
|
;; You should have received a copy of the GNU General Public License
|
||
|
|
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||
|
|
|
||
|
|
;;; Commentary:
|
||
|
|
|
||
|
|
;;
|
||
|
|
|
||
|
|
;;; Code:
|
||
|
|
|
||
|
|
(require 'lsp-mode)
|
||
|
|
(require 'dash)
|
||
|
|
|
||
|
|
(defgroup lsp-kubernetes-helm nil
|
||
|
|
"LSP support for YAML, using Helm Language Server (helm-ls)."
|
||
|
|
:group 'lsp-mode
|
||
|
|
:link '(url-link "https://github.com/mrjosh/helm-ls")
|
||
|
|
:package-version '(lsp-mode . "9.0.0"))
|
||
|
|
|
||
|
|
(defconst lsp-kubernetes-helm--lsp-configuration-section-name "helm-ls"
|
||
|
|
"Key used to grab the lsp configuration section for helm-ls.")
|
||
|
|
|
||
|
|
(defcustom lsp-kubernetes-helm-ls-server-path "helm_ls"
|
||
|
|
"Path to the Helm Language Server binary."
|
||
|
|
:group 'lsp-kubernetes-helm
|
||
|
|
:risky t
|
||
|
|
:type 'file)
|
||
|
|
|
||
|
|
(defcustom lsp-kubernetes-helm-ls-log-level "info"
|
||
|
|
"Options for the log level of the Helm Language Server."
|
||
|
|
:group 'lsp-kubernetes-helm
|
||
|
|
:type '(choice
|
||
|
|
(const "trace")
|
||
|
|
(const "debug")
|
||
|
|
(const "info")
|
||
|
|
(const "warning")
|
||
|
|
(const "error")
|
||
|
|
(const "fatal")
|
||
|
|
(const "panic"))
|
||
|
|
:package-version '(lsp-mode . "9.0.0"))
|
||
|
|
|
||
|
|
(defcustom lsp-kubernetes-helm-ls-main-values-file-path "values.yaml"
|
||
|
|
"Path to main values file for Helm Chart."
|
||
|
|
:group 'lsp-kubernetes-helm
|
||
|
|
:type 'file
|
||
|
|
:package-version '(lsp-mode . "9.0.0"))
|
||
|
|
|
||
|
|
(defcustom lsp-kubernetes-helm-overlay-values-file-path "values.lint.yaml"
|
||
|
|
"Path to values file that may be merged with main values files for Helm Chart."
|
||
|
|
:group 'lsp-kubernetes-helm
|
||
|
|
:type 'file
|
||
|
|
:package-version '(lsp-mode . "9.0.0"))
|
||
|
|
|
||
|
|
(defcustom lsp-kubernetes-helm-additional-values-files-pattern "values*.yaml"
|
||
|
|
"Pattern for additional values files, which will be shown for completion and hover."
|
||
|
|
:group 'lsp-kubernetes-helm
|
||
|
|
:type 'string
|
||
|
|
:package-version '(lsp-mode . "9.0.0"))
|
||
|
|
|
||
|
|
(defcustom lsp-kubernetes-helm-yaml-ls-server-path "yaml-language-server"
|
||
|
|
"Path to the Yaml Language Server binary that supports the Helm Language Server."
|
||
|
|
:group 'lsp-kubernetes-helm
|
||
|
|
:link '(url-link :tag "Yaml Language Server"
|
||
|
|
"https://github.com/redhat-developer/yaml-language-server")
|
||
|
|
:risky t
|
||
|
|
:type 'file)
|
||
|
|
|
||
|
|
(defcustom lsp-kubernetes-helm-yaml-ls-enable t
|
||
|
|
"Enable/disable default YAML Language Server."
|
||
|
|
:group 'lsp-kubernetes-helm
|
||
|
|
:type 'boolean
|
||
|
|
:package-version '(lsp-mode . "9.0.0"))
|
||
|
|
|
||
|
|
(defcustom lsp-kubernetes-helm-yaml-ls-enable-for-globs "*.{yaml,yml}"
|
||
|
|
"Enable/disable default YAML Language Server."
|
||
|
|
:group 'lsp-kubernetes-helm
|
||
|
|
:type 'string
|
||
|
|
:package-version '(lsp-mode . "9.0.0"))
|
||
|
|
|
||
|
|
(defcustom lsp-kubernetes-helm-yaml-ls-diagnostics-limit 25
|
||
|
|
"Limit the amount of yaml diagnostics to return.
|
||
|
|
Should typically be set to a low number when editing helm files."
|
||
|
|
:group 'lsp-kubernetes-helm
|
||
|
|
:type 'number
|
||
|
|
:package-version '(lsp-mode . "9.0.0"))
|
||
|
|
|
||
|
|
(defcustom lsp-kubernetes-helm-yaml-ls-schemas '((https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.30.3-standalone-strict/all.json
|
||
|
|
. ["*.y*"])
|
||
|
|
(kubernetes . [""]))
|
||
|
|
"List used by yaml language server to match schemas to globs.
|
||
|
|
This list is prioritized over the schema store schemas. Recommended to set
|
||
|
|
kubernetes to an empty string and at the end of the list to override the
|
||
|
|
default provided in yaml-language-server."
|
||
|
|
:group 'lsp-kubernetes-helm
|
||
|
|
:type '(alist :key-type (symbol :tag "schema") :value-type (lsp-repeatable-vector :tag "files (glob)"))
|
||
|
|
:package-version '(lsp-mode . "9.0.0"))
|
||
|
|
|
||
|
|
(defcustom lsp-kubernetes-helm-yaml-ls-format-enable t
|
||
|
|
"Enable/disable default YAML formatter."
|
||
|
|
:group 'lsp-kubernetes-helm
|
||
|
|
:type 'boolean
|
||
|
|
:package-version '(lsp-mode . "9.0.0"))
|
||
|
|
|
||
|
|
(defcustom lsp-kubernetes-helm-yaml-ls-single-quote nil
|
||
|
|
"Use single quote instead of double quotes."
|
||
|
|
:group 'lsp-kubernetes-helm
|
||
|
|
:type 'boolean
|
||
|
|
:package-version '(lsp-mode . "9.0.0"))
|
||
|
|
|
||
|
|
(defcustom lsp-kubernetes-helm-yaml-ls-bracket-spacing t
|
||
|
|
"Print spaces between brackets in objects."
|
||
|
|
:group 'lsp-kubernetes-helm
|
||
|
|
:type 'boolean
|
||
|
|
:package-version '(lsp-mode . "9.0.0"))
|
||
|
|
|
||
|
|
(defcustom lsp-kubernetes-helm-yaml-ls-prose-wrap "preserve"
|
||
|
|
"Options for prose-wrap.
|
||
|
|
Always: wrap prose if it exceeds the print width.
|
||
|
|
Never: never wrap the prose.
|
||
|
|
Preserve: wrap prose as-is."
|
||
|
|
:group 'lsp-kubernetes-helm
|
||
|
|
:type '(choice
|
||
|
|
(const "always")
|
||
|
|
(const "never")
|
||
|
|
(const "preserve"))
|
||
|
|
:package-version '(lsp-mode . "9.0.0"))
|
||
|
|
|
||
|
|
(defcustom lsp-kubernetes-helm-yaml-ls-print-width 80
|
||
|
|
"Specify the line length that the printer will wrap on."
|
||
|
|
:group 'lsp-kubernetes-helm
|
||
|
|
:type 'number
|
||
|
|
:package-version '(lsp-mode . "9.0.0"))
|
||
|
|
|
||
|
|
(defcustom lsp-kubernetes-helm-yaml-ls-validate t
|
||
|
|
"Enable/disable validation feature."
|
||
|
|
:group 'lsp-kubernetes-helm
|
||
|
|
:type 'boolean
|
||
|
|
:package-version '(lsp-mode . "9.0.0"))
|
||
|
|
|
||
|
|
(defcustom lsp-kubernetes-helm-yaml-ls-hover t
|
||
|
|
"Enable/disable hover feature."
|
||
|
|
:group 'lsp-kubernetes-helm
|
||
|
|
:type 'boolean
|
||
|
|
:package-version '(lsp-mode . "9.0.0"))
|
||
|
|
|
||
|
|
(defcustom lsp-kubernetes-helm-yaml-ls-completion t
|
||
|
|
"Enable/disable completion feature."
|
||
|
|
:group 'lsp-kubernetes-helm
|
||
|
|
:type 'boolean
|
||
|
|
:package-version '(lsp-mode . "9.0.0"))
|
||
|
|
|
||
|
|
(defcustom lsp-kubernetes-helm-yaml-ls-schema-store-extensions '(((name . "Kubernetes v1.30.3")
|
||
|
|
(description . "Kubernetes v1.30.3 manifest schema definition")
|
||
|
|
(url . "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.30.3-standalone-strict/all.json")))
|
||
|
|
"Schemas defined by user schemas to files in a glob pattern.
|
||
|
|
Used by Yaml Language Server to determine which schema to use for which types of files."
|
||
|
|
:group 'lsp-kubernetes-helm
|
||
|
|
:type '(list (list (alist
|
||
|
|
:key-type (choice
|
||
|
|
(const :tag "Name" name)
|
||
|
|
(const :tag "Description" description)
|
||
|
|
(const :tag "URL" url))
|
||
|
|
:value-type string)))
|
||
|
|
:package-version '(lsp-mode . "9.0.0"))
|
||
|
|
|
||
|
|
(defcustom lsp-kubernetes-helm-yaml-ls-schema-store-enable nil
|
||
|
|
"Enable/disable JSON Schema store. When set to true, available YAML \
|
||
|
|
schemas will be automatically pulled from
|
||
|
|
`lsp-kubernetes-helm-yaml-ls-schema-store-uri'."
|
||
|
|
:group 'lsp-kubernetes-helm
|
||
|
|
:type 'boolean
|
||
|
|
:package-version '(lsp-mode . "9.0.0"))
|
||
|
|
|
||
|
|
(defcustom lsp-kubernetes-helm-yaml-ls-schema-store-uri "https://www.schemastore.org/api/json/catalog.json"
|
||
|
|
"URL of schema store catalog to use."
|
||
|
|
:group 'lsp-kubernetes-helm
|
||
|
|
:type 'string
|
||
|
|
:package-version '(lsp-mode . "9.0.0"))
|
||
|
|
|
||
|
|
(defcustom lsp-kubernetes-helm-yaml-ls-schema-store-local-db
|
||
|
|
(expand-file-name
|
||
|
|
(locate-user-emacs-file
|
||
|
|
(f-join ".cache" "lsp" "lsp-kubernetes-helm-schemas.json")))
|
||
|
|
"Cached database of schema store."
|
||
|
|
:group 'lsp-kubernetes-helm
|
||
|
|
:type 'file
|
||
|
|
:package-version '(lsp-mode . "9.0.0"))
|
||
|
|
|
||
|
|
(defcustom lsp-kubernetes-helm-yaml-ls-custom-tags nil
|
||
|
|
"Custom tags for the parser to use."
|
||
|
|
:group 'lsp-kubernetes-helm
|
||
|
|
:type '(lsp-repeatable-vector string)
|
||
|
|
:package-version '(lsp-mode . "9.0.0"))
|
||
|
|
|
||
|
|
(defcustom lsp-kubernetes-helm-yaml-ls-max-items-computed 5000
|
||
|
|
"The maximum number of outline symbols and folding regions computed.
|
||
|
|
Limited for performance reasons."
|
||
|
|
:group 'lsp-kubernetes-helm
|
||
|
|
:type 'number
|
||
|
|
:package-version '(lsp-mode . "9.0.0"))
|
||
|
|
|
||
|
|
(defcustom lsp-kubernetes-helm-server-arguments '("serve" "--stdio")
|
||
|
|
"Command to start helm-ls. Minimally needs serve otherwise the server won't start properly."
|
||
|
|
:type '(repeat string)
|
||
|
|
:group 'lsp-kubernetes-helm
|
||
|
|
:package-version '(lsp-mode . "9.0.0"))
|
||
|
|
|
||
|
|
(defvar lsp-kubernetes-helm-yaml-ls--schema-store nil
|
||
|
|
"A list of schemas provided by schema store uri.")
|
||
|
|
|
||
|
|
(defun lsp-kubernetes-helm-download-or-refresh-schema-store-db (&optional force-download)
|
||
|
|
"Download remote schema store at `lsp-yaml-schema-store-uri' into local cache.
|
||
|
|
Set FORCE-DOWNLOAD to non-nil to force re-download the database.
|
||
|
|
FORCE-DOWNLOADING is set to t by default"
|
||
|
|
(interactive "P")
|
||
|
|
(let ((local-db-directory (file-name-directory lsp-kubernetes-helm-yaml-ls-schema-store-local-db))
|
||
|
|
(force-download (or force-download t)))
|
||
|
|
(when (not (file-exists-p lsp-kubernetes-helm-yaml-ls-schema-store-local-db))
|
||
|
|
(unless (file-directory-p local-db-directory)
|
||
|
|
(mkdir local-db-directory t))
|
||
|
|
(url-copy-file lsp-kubernetes-helm-yaml-ls-schema-store-uri lsp-kubernetes-helm-yaml-ls-schema-store-local-db force-download))))
|
||
|
|
|
||
|
|
(defun lsp-kubernetes-helm--get-available-schemas ()
|
||
|
|
"Get list of supported schemas."
|
||
|
|
(when (and lsp-kubernetes-helm-yaml-ls-schema-store-enable
|
||
|
|
(not lsp-kubernetes-helm-yaml-ls--schema-store))
|
||
|
|
(lsp-kubernetes-helm-download-or-refresh-schema-store-db nil)
|
||
|
|
(setq lsp-kubernetes-helm-yaml-ls--schema-store
|
||
|
|
(alist-get 'schemas (json-read-file lsp-kubernetes-helm-yaml-ls-schema-store-local-db))))
|
||
|
|
(seq-concatenate 'list lsp-kubernetes-helm-yaml-ls-schema-store-extensions lsp-kubernetes-helm-yaml-ls--schema-store))
|
||
|
|
|
||
|
|
(defun lsp-kubernetes-helm-set-buffer-schema (schema-uri-string)
|
||
|
|
"Set yaml schema for the current buffer to SCHEMA-URI-STRING.
|
||
|
|
Remove buffer from all other schema associations."
|
||
|
|
(interactive "MURI: ")
|
||
|
|
(let* ((schema-uri (intern schema-uri-string))
|
||
|
|
(buffer-file-path (file-relative-name
|
||
|
|
(lsp--uri-to-path (lsp--buffer-uri))
|
||
|
|
(lsp-workspace-root (lsp--buffer-uri))))
|
||
|
|
;; yaml language server can do partial path matching
|
||
|
|
(glob (concat "/" buffer-file-path))
|
||
|
|
(current-config (assoc schema-uri lsp-kubernetes-helm-yaml-ls-schemas))
|
||
|
|
(current-patterns (and current-config (cdr current-config))))
|
||
|
|
(if current-config
|
||
|
|
(or (member glob (append current-patterns nil))
|
||
|
|
(setq lsp-kubernetes-helm-yaml-ls-schemas
|
||
|
|
(cl-acons schema-uri
|
||
|
|
(vconcat (vector glob) current-patterns)
|
||
|
|
(assq-delete-all schema-uri (mapcar (lambda (x) (lsp-kubernetes-helm--remove-glob-from-all-schemas x glob)) lsp-kubernetes-helm-yaml-ls-schemas)))))
|
||
|
|
(setq lsp-kubernetes-helm-yaml-ls-schemas
|
||
|
|
(cl-acons schema-uri (vector glob) (mapcar (lambda (x) (lsp-kubernetes-helm--remove-glob-from-all-schemas x glob)) lsp-kubernetes-helm-yaml-ls-schemas))))
|
||
|
|
(lsp--set-configuration (lsp-configuration-section lsp-kubernetes-helm--lsp-configuration-section-name))))
|
||
|
|
|
||
|
|
(defun lsp-kubernetes-helm-select-buffer-schema ()
|
||
|
|
"Select schema for the current buffer based on the list of supported schemas."
|
||
|
|
(interactive)
|
||
|
|
(let* ((schema (lsp--completing-read "Select buffer schema: "
|
||
|
|
(lsp-kubernetes-helm--get-available-schemas)
|
||
|
|
(lambda (schema)
|
||
|
|
(format "%s: %s" (alist-get 'name schema)(alist-get 'description schema)))
|
||
|
|
nil t))
|
||
|
|
(uri (alist-get 'url schema)))
|
||
|
|
(lsp-kubernetes-helm-set-buffer-schema uri)))
|
||
|
|
|
||
|
|
(defun lsp-kubernetes-helm--remove-glob-from-all-schemas (schemas glob)
|
||
|
|
"Removes GLOB from all keys in SCHEMAS."
|
||
|
|
(let ((patterns (cdr schemas)))
|
||
|
|
(cons (car schemas)
|
||
|
|
(vconcat (-filter (lambda (p)
|
||
|
|
(not (equal p glob)))
|
||
|
|
(append patterns nil)) nil))))
|
||
|
|
|
||
|
|
(lsp-register-custom-settings
|
||
|
|
'(("helm-ls.logLevel" lsp-kubernetes-helm-ls-log-level)
|
||
|
|
("helm-ls.valuesFiles.mainValuesFile" lsp-kubernetes-helm-ls-main-values-file-path)
|
||
|
|
("helm-ls.valuesFiles.lintOverlayValuesFile" lsp-kubernetes-helm-overlay-values-file-path)
|
||
|
|
("helm-ls.valuesFiles.additionalValuesFilesGlobPattern" lsp-kubernetes-helm-additional-values-files-pattern)
|
||
|
|
("helm-ls.yamlls.enabled" lsp-kubernetes-helm-yaml-ls-enable t)
|
||
|
|
("helm-ls.yamlls.enabledForFilesGlob" lsp-kubernetes-helm-yaml-ls-enable-for-globs)
|
||
|
|
("helm-ls.yamlls.diagnosticsLimit" lsp-kubernetes-helm-yaml-ls-diagnostics-limit)
|
||
|
|
("helm-ls.yamlls.path" lsp-kubernetes-helm-yaml-ls-server-path)
|
||
|
|
("helm-ls.yamlls.config.format.enable" lsp-kubernetes-helm-yaml-ls-format-enable t)
|
||
|
|
("helm-ls.yamlls.config.format.singleQuote" lsp-kubernetes-helm-yaml-ls-single-quote t)
|
||
|
|
("helm-ls.yamlls.config.format.bracketSpacing" lsp-kubernetes-helm-yaml-ls-bracket-spacing)
|
||
|
|
("helm-ls.yamlls.config.format.proseWrap" lsp-kubernetes-helm-yaml-ls-prose-wrap)
|
||
|
|
("helm-ls.yamlls.config.format.printWidth" lsp-kubernetes-helm-yaml-ls-print-width)
|
||
|
|
("helm-ls.yamlls.config.validate" lsp-kubernetes-helm-yaml-ls-validate t)
|
||
|
|
("helm-ls.yamlls.config.hover" lsp-kubernetes-helm-yaml-ls-hover t)
|
||
|
|
("helm-ls.yamlls.config.completion" lsp-kubernetes-helm-yaml-ls-completion t)
|
||
|
|
("helm-ls.yamlls.config.schemas" lsp-kubernetes-helm-yaml-ls-schemas)
|
||
|
|
("helm-ls.yamlls.config.schemaStore.enable" lsp-kubernetes-helm-yaml-ls-schema-store-enable nil)
|
||
|
|
("helm-ls.yamlls.config.schemaStore.url" lsp-kubernetes-helm-yaml-ls-schema-store-uri)
|
||
|
|
("helm-ls.yamlls.config.customTags" lsp-kubernetes-helm-yaml-ls-custom-tags)
|
||
|
|
("helm-ls.yamlls.config.maxItemsComputed" lsp-kubernetes-helm-yaml-ls-max-items-computed)))
|
||
|
|
|
||
|
|
(lsp-dependency 'kubernetes-helm-language-server
|
||
|
|
`(:system ,lsp-kubernetes-helm-ls-server-path)
|
||
|
|
`(:system ,lsp-kubernetes-helm-yaml-ls-server-path)
|
||
|
|
`(:npm :package "yaml-language-server"
|
||
|
|
:path ,lsp-kubernetes-helm-yaml-ls-server-path))
|
||
|
|
|
||
|
|
(lsp-register-client
|
||
|
|
(make-lsp-client :new-connection (lsp-stdio-connection
|
||
|
|
(lambda ()
|
||
|
|
`(,(or (executable-find lsp-kubernetes-helm-ls-server-path)
|
||
|
|
(lsp-package-path 'kubernetes-helm-language-server))
|
||
|
|
,@lsp-kubernetes-helm-server-arguments)))
|
||
|
|
:activation-fn (lsp-activate-on "helm-ls")
|
||
|
|
:priority 0
|
||
|
|
:server-id 'helm-ls
|
||
|
|
:initialized-fn (lambda (workspace)
|
||
|
|
(with-lsp-workspace workspace
|
||
|
|
(lsp--set-configuration
|
||
|
|
(lsp-configuration-section lsp-kubernetes-helm--lsp-configuration-section-name))))))
|
||
|
|
|
||
|
|
(lsp-consistency-check lsp-kubernetes-helm)
|
||
|
|
|
||
|
|
(provide 'lsp-kubernetes-helm)
|
||
|
|
;;; lsp-kubernetes-helm.el ends here
|