;;; lsp-go.el --- Go Client settings -*- lexical-binding: t; -*- ;; Copyright (C) 2019 Muir Manders ;; Author: Muir Manders ;; Keywords: ;; 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 . ;;; Commentary: ;; lsp-go client ;;; Code: (require 'lsp-mode) (require 'lsp-completion) (defgroup lsp-go nil "LSP support for the Go Programming Language, using the gopls language server." :link '(url-link "https://github.com/golang/tools/blob/master/gopls/README.md") :group 'lsp-mode :package-version '(lsp-mode . "6.3.2")) (define-obsolete-variable-alias 'lsp-gopls-server-path 'lsp-go-gopls-server-path "lsp-mode 7.0.1") (defcustom lsp-go-gopls-server-path "gopls" "Path to gopls server binary." :type 'string :group 'lsp-go) (define-obsolete-variable-alias 'lsp-gopls-server-args 'lsp-go-gopls-server-args "lsp-mode 7.0.1") (defcustom lsp-go-gopls-server-args '("-remote=auto") "Extra CLI arguments for gopls." :type '(repeat string) :group 'lsp-go) (define-obsolete-variable-alias 'lsp-gopls-use-placeholders 'lsp-go-use-placeholders "lsp-mode 7.0.1") (defcustom lsp-go-use-placeholders t "Cause gopls to provide placeholder parameter snippets when completing function calls." :type 'boolean :group 'lsp-go) (define-obsolete-variable-alias 'lsp-gopls-build-flags 'lsp-go-build-flags "lsp-mode 7.0.1") (defcustom lsp-go-build-flags [] "A vector of flags passed on to the build system when invoked, applied to queries like `go list'." :type 'lsp-string-vector :group 'lsp-go :risky t :package-version '(lsp-mode "6.2")) (define-obsolete-variable-alias 'lsp-gopls-env 'lsp-go-env "lsp-mode 7.0.1") (defcustom lsp-go-env nil "`gopls' has the unusual ability to set environment variables, intended to affect the behavior of commands invoked by `gopls' on the user's behalf. This variable takes a hash table of env var names to desired values." :type '(alist :key-type (symbol :tag "env var name") :value-type (string :tag "value")) :group 'lsp-go :risky t :package-version '(lsp-mode "6.2")) (defcustom lsp-go-directory-filters [] "A vector of directory filters." :link '(url-link "https://github.com/golang/tools/blob/67e49ef2d0f326051e22a4a55bdf9344ae1a8ed8/gopls/doc/settings.md#directoryfilters-string") :group 'lsp-go :type 'lsp-string-vector :package-version '(lsp-mode "8.0.0")) (define-obsolete-variable-alias 'lsp-gopls-hover-kind 'lsp-go-hover-kind "lsp-mode 7.0.1") (defcustom lsp-go-hover-kind "SynopsisDocumentation" "`gopls' allows the end user to select the desired amount of documentation returned during e.g. hover and thing-at-point operations." :type '(choice (const "SynopsisDocumentation") (const "NoDocumentation") (const "FullDocumentation") (const "SingleLine") (const "Structured")) :group 'lsp-go :risky t :package-version '(lsp-mode "6.2")) (define-obsolete-variable-alias 'lsp-gopls-available-codelens 'lsp-go-available-codelenses "lsp-mode 7.0.1") (define-obsolete-variable-alias 'lsp-go-available-codelens 'lsp-go-available-codelenses "lsp-mode 7.0.1") (defvar lsp-go-available-codelenses '( (gc_details . "Toggle the calculation of gc annotations") (generate . "Run `go generate` for a directory") (regenerate_cgo . "Regenerate cgo definitions") (test . "Run `go test` for a specific set of test or benchmark functions (legacy)") (tidy . "Run `go mod tidy` for a module") (upgrade_dependency . "Upgrade a dependency") (vendor . "Runs `go mod vendor' for a module")) "Available codelenses that can be further enabled or disabled through `lsp-go-codelenses'.") (defun lsp-go--defcustom-available-as-alist-type (alist) "Return a list for the `:type' field in `defcustom' used to populate an alist. The input ALIST has the form `((\"name\" . \"documentation sentence\") [...])' The returned type provides a tri-state that either: - does not include the element in the alist - sets element to false (actually, :json-false) - sets element to true \(actually, t)" (let ((list '())) (dolist (v alist) (push `(cons :tag ,(cdr v) (const :format "" ,(car v)) (choice (const :tag "Enable" t) (const :tag "Disable" :json-false))) list)) (push 'set list) list)) (define-obsolete-variable-alias 'lsp-gopls-codelens 'lsp-go-codelenses "lsp-mode 7.0.1") (define-obsolete-variable-alias 'lsp-go-codelens 'lsp-go-codelenses "lsp-mode 7.0.1") (defcustom lsp-go-codelenses '((gc_details . :json-false) (generate . t) (regenerate_cgo . t) (tidy . t) (upgrade_dependency . t) (test . t) (vendor . t)) "Select what codelenses should be enabled or not. The codelenses can be found at https://github.com/golang/tools/blob/3fa0e8f87c1aae0a9adc2a63af1a1945d16d9359/internal/lsp/source/options.go#L106-L112." :type (lsp-go--defcustom-available-as-alist-type lsp-go-available-codelenses) :group 'lsp-go :risky t :package-version '(lsp-mode "7.0")) (define-obsolete-variable-alias 'lsp-clients-go-library-directories 'lsp-go-library-directories "lsp-mode 7.0.1") (defcustom lsp-go-library-directories '("/usr") "List of directories which will be considered to be libraries." :group 'lsp-go :risky t :type '(repeat string)) (define-obsolete-variable-alias 'lsp-clients-go-library-directories-include-go-modules 'lsp-go-library-directories-include-go-modules "lsp-mode 7.0.1") (defcustom lsp-go-library-directories-include-go-modules t "Whether or not $GOPATH/pkg/mod should be included as a library directory." :type 'boolean :group 'lsp-go) (defun lsp-go--library-default-directories (_workspace) "Calculate go library directories. If `lsp-go-library-directories-include-go-modules' is non-nil and the environment variable GOPATH is set this function will return $GOPATH/pkg/mod along with the value of `lsp-go-library-directories'." (let ((library-dirs lsp-go-library-directories)) (when (and lsp-go-library-directories-include-go-modules (or (and (not (file-remote-p default-directory)) (executable-find "go")) (and (version<= "27.0" emacs-version) (with-no-warnings (executable-find "go" (file-remote-p default-directory)))))) (with-temp-buffer (when (zerop (process-file "go" nil t nil "env" "GOPATH")) (setq library-dirs (append library-dirs (list (concat (string-trim-right (buffer-substring (point-min) (point-max))) "/pkg/mod"))))))) (if (file-remote-p default-directory) (mapcar (lambda (path) (concat (file-remote-p default-directory) path)) library-dirs) library-dirs))) (defcustom lsp-go-link-target "pkg.go.dev" "Which website to use for displaying Go documentation." :type '(choice (const "pkg.go.dev") (string :tag "A custom website")) :group 'lsp-go :package-version '(lsp-mode "7.0.1")) (defcustom lsp-go-links-in-hover t "If non-nil, hover documentation includes links." :type 'boolean :group 'lsp-go :package-version '(lsp-mode "8.0.0")) (defcustom lsp-go-use-gofumpt nil "If non-nil, use gofumpt formatting." :type 'boolean :group 'lsp-go :package-version '(lsp-mode "8.0.0")) (defcustom lsp-go-goimports-local "" "Equivalent of the goimports -local flag, which puts imports beginning with this string after third-party packages. It should be the prefix of the import path whose imports should be grouped separately." :type 'string :group 'lsp-go :package-version '(lsp-mode "8.0.0")) (defcustom lsp-go-analyses nil "Specify analyses that the user would like to enable or disable. A map of the names of analysis passes that should be enabled/disabled. A full list of analyzers that gopls uses can be found at https://github.com/golang/tools/blob/master/gopls/doc/analyzers.md" :type '(alist :key-type (string :tag "analyzer name") :value-type (boolean :tag "value")) :group 'lsp-go :risky t :package-version '(lsp-mode "8.0.0")) (defcustom lsp-go-import-shortcut "Both" "Specifies whether import statements should link to documentation or go to definitions." :type '(choice (const "Both") (const "Link") (const "Definition")) :group 'lsp-go :risky t :package-version '(lsp-mode "8.0.0")) (defcustom lsp-go-symbol-matcher "Fuzzy" "Sets the algorithm that is used when finding workspace symbols." :type '(choice (const "Fuzzy") (const "CaseInsensitive") (const "CaseSensitive")) :group 'lsp-go :risky t :package-version '(lsp-mode "8.0.0")) (defcustom lsp-go-symbol-style "Dynamic" "Controls how symbols are qualified in symbol responses. 'Dynamic' uses whichever qualifier results in the highest scoring match for the given symbol query. Here a 'qualifier' is any '/' or '.' delimited suffix of the fully qualified symbol. i.e. 'to/pkg.Foo.Field' or just 'Foo.Field'. 'Full' is fully qualified symbols, i.e. 'path/to/pkg.Foo.Field'. 'Package' is package qualified symbols i.e. 'pkg.Foo.Field'." :type '(choice (const "Dynamic") (const "Full") (const "Package")) :group 'lsp-go :risky t :package-version '(lsp-mode "8.0.0")) (lsp-register-custom-settings '(("gopls.usePlaceholders" lsp-go-use-placeholders t) ("gopls.hoverKind" lsp-go-hover-kind) ("gopls.buildFlags" lsp-go-build-flags) ("gopls.env" lsp-go-env) ("gopls.linkTarget" lsp-go-link-target) ("gopls.codelenses" lsp-go-codelenses) ("gopls.linksInHover" lsp-go-links-in-hover t) ("gopls.gofumpt" lsp-go-use-gofumpt t) ("gopls.local" lsp-go-goimports-local) ("gopls.directoryFilters" lsp-go-directory-filters) ("gopls.analyses" lsp-go-analyses) ("gopls.importShortcut" lsp-go-import-shortcut) ("gopls.symbolMatcher" lsp-go-symbol-matcher) ("gopls.symbolStyle" lsp-go-symbol-style))) (lsp-register-client (make-lsp-client :new-connection (lsp-stdio-connection (lambda () (cons lsp-go-gopls-server-path lsp-go-gopls-server-args))) :activation-fn (lsp-activate-on "go" "go.mod") :language-id "go" :priority 0 :server-id 'gopls :completion-in-comments? t :library-folders-fn #'lsp-go--library-default-directories :after-open-fn (lambda () ;; https://github.com/golang/tools/commit/b2d8b0336 (setq-local lsp-completion-filter-on-incomplete nil)))) (lsp-consistency-check lsp-go) (provide 'lsp-go) ;;; lsp-go.el ends here