Modernize lsp-mode integration

* switch the company-backend used by lsp-mode from company-lsp to
company-capf (said to provide better performance and allows us to remove
the dependency on company-lsp)

* when available (on recent builds of Emacs 27+), lsp-mode buffers will
now use a larger than default value of `read-process-output-max`.
According to the lsp-mode performance guide, this can also significantly
improve lsp-mode performance

* flycheck support recently moved into lsp proper; with this commit,
the lsp module follows suit and prefers lsp-flycheck over
lsp-ui-flycheck

* if the new module flag `+no-peek` is set, doom-emacs will now use the xref
backend for reference and definition lookup instead of the lsp-ui-peek-*
backend offered by lsp-ui-mode
This commit is contained in:
Sebastian Sturm 2020-02-23 16:37:16 +01:00 committed by Sebastian Sturm
parent ca1a614e63
commit 998dccd8fe
4 changed files with 62 additions and 46 deletions

View file

@ -162,7 +162,7 @@ Small modules that give Emacs access to external tools & services.
+ gist - TODO
+ [[file:../modules/tools/lookup/README.org][lookup]] =+dictionary +docsets= - Universal jump-to & documentation lookup
backend
+ [[file:../modules/tools/lsp/README.org][lsp]] - TODO
+ [[file:../modules/tools/lsp/README.org][lsp]] =+peek= - TODO
+ macos - TODO
+ magit - TODO
+ make - TODO

View file

@ -52,12 +52,11 @@ As of this writing, this is the state of LSP support in Doom Emacs:
| [[../../lang/web/README.org][:lang web]] | web-mode, css-mode, scss-mode, sass-mode, less-css-mode | vscode-css-languageserver-bin, vscode-html-languageserver-bin |
** Module Flags
This module provides no flags.
+ =+peek= Enables the =lsp-ui-peek= navigation frontend provided by the =lsp-ui= package.
** Plugins
+ [[https://github.com/emacs-lsp/lsp-mode][lsp-mode]]
+ [[https://github.com/emacs-lsp/lsp-ui][lsp-ui]]
+ [[https://github.com/tigersoldier/company-lsp][company-lsp]]*
* Prerequisites
This module has no direct prerequisites, but major-modes require you to install

View file

@ -1,11 +1,20 @@
;;; tools/lsp/config.el -*- lexical-binding: t; -*-
(defvar +lsp-company-backend 'company-lsp
"What backend to prepend to `company-backends' when `lsp-mode' is active.
"What backend to use for lsp-driven autocompletion, unless
overridden by `+lsp-capf-blacklist'.
This can be a single company backend or a list thereof. It can be anything
`company-backends' will accept.")
While `company-capf' does not require the `company-lsp' package
and should offer better performance, it has been integrated into
lsp only recently and as of 02/25/2020 is known to cause issues
with some language servers. If you wish to use `company-capf' in
general but fall back to `company-lsp' for specific language
servers, set `+lsp-company-backend' to `company-capf' and add the
excluded servers' identifiers to `+lsp-capf-blacklist'.")
(defvar +lsp-capf-blacklist '(ts-ls gopls)
"Language servers listed here will always use the `company-lsp' backend,
irrespective of what `+lsp-company-backend' is set to.")
;;
;;; Packages
@ -20,6 +29,42 @@ This can be a single company backend or a list thereof. It can be anything
;; Auto-kill LSP server once you've killed the last buffer associated with its
;; project.
(setq lsp-keep-workspace-alive nil)
(add-hook! 'lsp-mode-hook
(defun +lsp-init-company-h ()
(if (not (bound-and-true-p company-mode))
(add-hook 'company-mode-hook #'+lsp-init-company-h t t)
(let ((preferred-backend +lsp-company-backend))
(lsp-foreach-workspace
(when (memq (lsp--client-server-id (lsp--workspace-client lsp--cur-workspace))
+lsp-capf-blacklist)
(setq preferred-backend 'company-lsp)))
(if (eq 'company-capf preferred-backend)
;; use capf backend
(progn
(setq-local lsp-enable-completion-at-point t)
(setq-local lsp-prefer-capf t)
(setq-local company-backends
(cons 'company-capf (remq 'company-capf company-backends))))
;; use company-lsp backend (may need to be loaded first)
(require 'company-lsp)
(setq-local lsp-enable-completion-at-point nil)
(setq-local lsp-prefer-capf nil)
(setq-local company-backends
(cons 'company-lsp (remq 'company-capf company-backends)))
(setq-default company-lsp-cache-candidates 'auto))
(remove-hook 'company-mode-hook #'+lsp-init-company-h t))))
(defun +lsp-init-flycheck-or-flymake-h ()
"Set up flycheck-mode or flymake-mode, depending on `lsp-diagnostic-package'."
(cond ((eq :none lsp-diagnostic-package))
((or (eq :flymake lsp-diagnostic-package)
(eq t lsp-diagnostic-package))
(lsp--flymake-setup))
((require 'flycheck nil t)
(let ((old-checker flycheck-checker))
(lsp-flycheck-enable t)
(when old-checker
(setq-local flycheck-checker old-checker)
(kill-local-variable 'flycheck-check-syntax-automatically)))))))
;; For `lsp-clients'
(setq lsp-server-install-dir (concat doom-etc-dir "lsp/")
@ -79,7 +124,7 @@ modules.
Also see:
+ `+lsp-init-company-h' (on `lsp-mode-hook')
+ `+lsp-init-ui-flycheck-or-flymake-h' (on `lsp-ui-mode-hook')
+ `+lsp-init-flycheck-or-flymake-h' (on `lsp-mode-hook')
This also logs the resolved project root, if found, so we know where we are."
:override #'lsp
@ -92,6 +137,10 @@ This also logs the resolved project root, if found, so we know where we are."
(lsp--try-project-root-workspaces
(equal arg '(4))
(and arg (not (equal arg 1))))))
;; read-process-output-max is only available on recent
;; development builds of Emacs 27 and above
(when (boundp 'read-process-output-max)
(setq-local read-process-output-max (* 1024 1024)))
(prog1 (lsp-mode 1)
(setq-local lsp-buffer-uri (lsp--buffer-uri))
;; Announce what project root we're using, for diagnostic purposes
@ -110,24 +159,9 @@ This also logs the resolved project root, if found, so we know where we are."
(use-package! lsp-ui
:hook (lsp-mode . lsp-ui-mode)
:init
(add-hook! 'lsp-ui-mode-hook
(defun +lsp-init-ui-flycheck-or-flymake-h ()
"Sets up flymake-mode or flycheck-mode, depending on `lsp-prefer-flymake'."
(cond ((eq :none lsp-prefer-flymake))
(lsp-prefer-flymake
(lsp--flymake-setup))
((require 'flycheck nil t)
(require 'lsp-ui-flycheck)
(let ((old-checker flycheck-checker))
(lsp-ui-flycheck-enable t)
(when old-checker
(setq-local flycheck-checker old-checker)
(kill-local-variable 'flycheck-check-syntax-automatically)))))))
:config
(setq lsp-prefer-flymake nil
lsp-ui-doc-max-height 8
(setq lsp-ui-doc-max-height 8
lsp-ui-doc-max-width 35
lsp-ui-sideline-ignore-duplicate t
;; lsp-ui-doc is redundant with and more invasive than
@ -138,27 +172,10 @@ This also logs the resolved project root, if found, so we know where we are."
;; errors flash briefly and then disappear).
lsp-ui-sideline-show-hover nil)
(set-lookup-handlers! 'lsp-ui-mode :async t
:definition 'lsp-ui-peek-find-definitions
:references 'lsp-ui-peek-find-references))
(use-package! company-lsp
:when (featurep! :completion company)
:defer t
:init
;; Make sure that `company-capf' is disabled since it is incompatible with
;; `company-lsp' (see lsp-mode#884)
(add-hook! 'lsp-mode-hook
(defun +lsp-init-company-h ()
(if (not (bound-and-true-p company-mode))
(add-hook 'company-mode-hook #'+lsp-init-company-h t t)
(setq-local company-backends
(cons +lsp-company-backend
(remq 'company-capf company-backends)))
(remove-hook 'company-mode-hook #'+lsp-init-company-h t))))
:config
(setq company-lsp-cache-candidates 'auto)) ;; cache candidates for better performance
(when (featurep! +peek)
(set-lookup-handlers! 'lsp-ui-mode :async t
:definition 'lsp-ui-peek-find-definitions
:references 'lsp-ui-peek-find-references)))
(use-package! helm-lsp

View file

@ -1,8 +1,8 @@
;; -*- no-byte-compile: t; -*-
;;; tools/lsp/packages.el
(package! lsp-mode :pin "2fc0963a50")
(package! lsp-ui :pin "e8200e3b72")
(package! lsp-mode :pin "fc812bea1f")
(package! lsp-ui :pin "da9788b427")
(when (featurep! :completion company)
(package! company-lsp :pin "f921ffa0cd"))
(when (featurep! :completion ivy)