2020-05-28 11:03:49 +02:00
|
|
|
;;; tools/lsp/+lsp.el -*- lexical-binding: t; -*-
|
|
|
|
|
2021-05-16 21:17:16 -04:00
|
|
|
(defvar +lsp-company-backends
|
|
|
|
(if (featurep! :editor snippets)
|
2021-08-03 22:45:59 -04:00
|
|
|
'(:separate company-capf company-yasnippet)
|
2021-05-16 21:17:16 -04:00
|
|
|
'company-capf)
|
2020-08-01 15:18:02 -04:00
|
|
|
"The backends to prepend to `company-backends' in `lsp-mode' buffers.
|
|
|
|
Can be a list of backends; accepts any value `company-backends' accepts.")
|
|
|
|
|
2021-02-05 21:53:06 -05:00
|
|
|
(defvar +lsp-prompt-to-install-server t
|
2021-02-24 15:54:28 -05:00
|
|
|
"If non-nil, prompt to install a server if no server is present.
|
|
|
|
|
|
|
|
If set to `quiet', suppress the install prompt and don't visibly inform the user
|
|
|
|
about it (it will be logged to *Messages* however).")
|
2021-02-05 21:53:06 -05:00
|
|
|
|
2020-08-01 15:18:02 -04:00
|
|
|
|
|
|
|
;;
|
|
|
|
;;; Packages
|
|
|
|
|
2020-05-28 11:03:49 +02:00
|
|
|
(use-package! lsp-mode
|
|
|
|
:commands lsp-install-server
|
|
|
|
:init
|
2020-10-11 18:13:59 -04:00
|
|
|
;; Don't touch ~/.emacs.d, which could be purged without warning
|
|
|
|
(setq lsp-session-file (concat doom-etc-dir "lsp-session")
|
2021-04-15 01:21:07 -04:00
|
|
|
lsp-server-install-dir (concat doom-etc-dir "lsp"))
|
2020-08-06 17:40:06 -04:00
|
|
|
;; Don't auto-kill LSP server after last workspace buffer is killed, because I
|
|
|
|
;; will do it for you, after `+lsp-defer-shutdown' seconds.
|
|
|
|
(setq lsp-keep-workspace-alive nil)
|
2020-05-28 11:03:49 +02:00
|
|
|
|
2020-08-06 17:40:06 -04:00
|
|
|
;; NOTE I tweak LSP's defaults in order to make its more expensive or imposing
|
|
|
|
;; features opt-in. Some servers implement these poorly and, in most
|
|
|
|
;; cases, it's safer to rely on Emacs' native mechanisms (eldoc vs
|
|
|
|
;; lsp-ui-doc, open in popup vs sideline, etc).
|
|
|
|
|
|
|
|
;; Disable features that have great potential to be slow.
|
2020-10-11 18:13:59 -04:00
|
|
|
(setq lsp-enable-folding nil
|
2020-08-06 17:40:06 -04:00
|
|
|
lsp-enable-text-document-color nil)
|
2020-10-11 18:13:59 -04:00
|
|
|
;; Reduce unexpected modifications to code
|
|
|
|
(setq lsp-enable-on-type-formatting nil)
|
2021-01-06 20:55:36 -05:00
|
|
|
;; Make breadcrumbs opt-in; they're redundant with the modeline and imenu
|
|
|
|
(setq lsp-headerline-breadcrumb-enable nil)
|
2020-08-06 17:40:06 -04:00
|
|
|
|
2020-10-11 18:13:59 -04:00
|
|
|
;; Let doom bind the lsp keymap.
|
|
|
|
(when (featurep! :config default +bindings)
|
|
|
|
(setq lsp-keymap-prefix nil))
|
2020-05-28 11:03:49 +02:00
|
|
|
|
|
|
|
:config
|
2021-05-16 21:17:16 -04:00
|
|
|
(add-to-list 'doom-debug-variables 'lsp-log-io)
|
2020-08-21 00:09:59 -04:00
|
|
|
|
2021-03-27 17:58:30 -04:00
|
|
|
(setq lsp-intelephense-storage-path (concat doom-etc-dir "lsp-intelephense/")
|
2021-04-15 01:21:07 -04:00
|
|
|
lsp-vetur-global-snippets-dir
|
|
|
|
(expand-file-name
|
|
|
|
"vetur" (or (bound-and-true-p +snippets-dir)
|
|
|
|
(concat doom-private-dir "snippets/")))
|
|
|
|
lsp-xml-jar-file (expand-file-name "org.eclipse.lsp4xml-0.3.0-uber.jar" lsp-server-install-dir)
|
|
|
|
lsp-groovy-server-file (expand-file-name "groovy-language-server-all.jar" lsp-server-install-dir))
|
2020-08-06 17:40:06 -04:00
|
|
|
|
2021-07-12 20:15:29 -04:00
|
|
|
;; REVIEW Remove this once this is fixed upstream.
|
|
|
|
(add-to-list 'lsp-client-packages 'lsp-racket)
|
|
|
|
|
2021-07-29 08:59:48 +07:00
|
|
|
(add-hook! 'doom-escape-hook
|
|
|
|
(defun +lsp-signature-stop-maybe-h ()
|
|
|
|
"Close the displayed `lsp-signature'."
|
|
|
|
(when lsp-signature-mode
|
|
|
|
(lsp-signature-stop)
|
|
|
|
t)))
|
|
|
|
|
2020-05-28 11:03:49 +02:00
|
|
|
(set-popup-rule! "^\\*lsp-help" :size 0.35 :quit t :select t)
|
2021-03-27 21:41:15 -04:00
|
|
|
(set-lookup-handlers! 'lsp-mode
|
|
|
|
:definition #'+lsp-lookup-definition-handler
|
|
|
|
:references #'+lsp-lookup-references-handler
|
2021-04-17 07:58:50 +08:00
|
|
|
:documentation '(lsp-describe-thing-at-point :async t)
|
2021-04-17 08:54:50 +08:00
|
|
|
:implementations '(lsp-find-implementation :async t)
|
2021-03-05 18:43:56 -05:00
|
|
|
:type-definition #'lsp-find-type-definition)
|
2020-05-28 11:03:49 +02:00
|
|
|
|
2020-10-11 19:44:00 -04:00
|
|
|
(defadvice! +lsp--respect-user-defined-checkers-a (orig-fn &rest args)
|
|
|
|
"Ensure user-defined `flycheck-checker' isn't overwritten by `lsp'."
|
2020-10-20 16:51:39 -04:00
|
|
|
:around #'lsp-diagnostics-flycheck-enable
|
2020-10-11 19:44:00 -04:00
|
|
|
(if flycheck-checker
|
|
|
|
(let ((old-checker flycheck-checker))
|
|
|
|
(apply orig-fn args)
|
|
|
|
(setq-local flycheck-checker old-checker))
|
|
|
|
(apply orig-fn args)))
|
|
|
|
|
2020-05-28 11:03:49 +02:00
|
|
|
(add-hook! 'lsp-mode-hook
|
2020-08-06 17:40:06 -04:00
|
|
|
(defun +lsp-display-guessed-project-root-h ()
|
|
|
|
"Log what LSP things is the root of the current project."
|
|
|
|
;; Makes it easier to detect root resolution issues.
|
|
|
|
(when-let (path (buffer-file-name (buffer-base-buffer)))
|
|
|
|
(if-let (root (lsp--calculate-root (lsp-session) path))
|
|
|
|
(lsp--info "Guessed project root is %s" (abbreviate-file-name root))
|
2020-08-11 21:10:35 -04:00
|
|
|
(lsp--info "Could not guess project root."))))
|
2020-10-11 18:13:59 -04:00
|
|
|
#'+lsp-optimization-mode)
|
2020-08-06 17:40:06 -04:00
|
|
|
|
2021-05-01 13:03:07 +02:00
|
|
|
(when (featurep! :completion company)
|
|
|
|
(add-hook! 'lsp-completion-mode-hook
|
|
|
|
(defun +lsp-init-company-backends-h ()
|
|
|
|
(when lsp-completion-mode
|
|
|
|
(set (make-local-variable 'company-backends)
|
|
|
|
(cons +lsp-company-backends
|
|
|
|
(remove +lsp-company-backends
|
|
|
|
(remq 'company-capf company-backends))))))))
|
2020-05-28 11:03:49 +02:00
|
|
|
|
|
|
|
(defvar +lsp--deferred-shutdown-timer nil)
|
|
|
|
(defadvice! +lsp-defer-server-shutdown-a (orig-fn &optional restart)
|
|
|
|
"Defer server shutdown for a few seconds.
|
|
|
|
This gives the user a chance to open other project files before the server is
|
2020-08-06 17:40:06 -04:00
|
|
|
auto-killed (which is a potentially expensive process). It also prevents the
|
|
|
|
server getting expensively restarted when reverting buffers."
|
2020-05-28 11:03:49 +02:00
|
|
|
:around #'lsp--shutdown-workspace
|
|
|
|
(if (or lsp-keep-workspace-alive
|
|
|
|
restart
|
|
|
|
(null +lsp-defer-shutdown)
|
|
|
|
(= +lsp-defer-shutdown 0))
|
2020-10-11 18:13:59 -04:00
|
|
|
(prog1 (funcall orig-fn restart)
|
|
|
|
(+lsp-optimization-mode -1))
|
2020-05-28 11:03:49 +02:00
|
|
|
(when (timerp +lsp--deferred-shutdown-timer)
|
|
|
|
(cancel-timer +lsp--deferred-shutdown-timer))
|
|
|
|
(setq +lsp--deferred-shutdown-timer
|
|
|
|
(run-at-time
|
|
|
|
(if (numberp +lsp-defer-shutdown) +lsp-defer-shutdown 3)
|
|
|
|
nil (lambda (workspace)
|
2020-10-20 16:52:39 -04:00
|
|
|
(with-lsp-workspace workspace
|
|
|
|
(unless (lsp--workspace-buffers workspace)
|
2020-10-12 17:36:02 -04:00
|
|
|
(let ((lsp-restart 'ignore))
|
|
|
|
(funcall orig-fn))
|
2020-10-11 18:13:59 -04:00
|
|
|
(+lsp-optimization-mode -1))))
|
2021-02-05 21:53:06 -05:00
|
|
|
lsp--cur-workspace))))
|
|
|
|
|
|
|
|
(defadvice! +lsp-dont-prompt-to-install-servers-maybe-a (orig-fn &rest args)
|
|
|
|
:around #'lsp
|
|
|
|
(when (buffer-file-name)
|
2021-03-05 18:50:23 -05:00
|
|
|
(require 'lsp-mode)
|
|
|
|
(lsp--require-packages)
|
2021-02-05 21:53:06 -05:00
|
|
|
(if (or (lsp--filter-clients
|
|
|
|
(-andfn #'lsp--matching-clients?
|
|
|
|
#'lsp--server-binary-present?))
|
2021-02-24 15:54:28 -05:00
|
|
|
(not (memq +lsp-prompt-to-install-server '(nil quiet))))
|
2021-02-05 21:53:06 -05:00
|
|
|
(apply orig-fn args)
|
2021-02-25 12:40:07 -05:00
|
|
|
;; HACK `lsp--message' overrides `inhibit-message', so use `quiet!'
|
|
|
|
(let ((doom-debug-p
|
|
|
|
(or doom-debug-p
|
|
|
|
(not (eq +lsp-prompt-to-install-server 'quiet)))))
|
|
|
|
(doom-shut-up-a #'lsp--info "No language server available for %S"
|
2020-06-05 21:42:36 -03:00
|
|
|
major-mode)))))
|
|
|
|
|
|
|
|
(when (featurep! :ui modeline +light)
|
|
|
|
(defvar-local lsp-modeline-icon nil)
|
|
|
|
|
|
|
|
(add-hook! '(lsp-before-initialize-hook
|
|
|
|
lsp-after-initialize-hook
|
|
|
|
lsp-after-uninitialized-functions
|
|
|
|
lsp-before-open-hook
|
|
|
|
lsp-after-open-hook)
|
|
|
|
(defun +lsp-update-modeline (&rest _)
|
|
|
|
"Update modeline with lsp state."
|
|
|
|
(let* ((workspaces (lsp-workspaces))
|
|
|
|
(face (if workspaces 'success 'warning))
|
|
|
|
(label (if workspaces "LSP Connected" "LSP Disconnected")))
|
|
|
|
(setq lsp-modeline-icon (concat
|
|
|
|
" "
|
|
|
|
(+modeline-format-icon 'faicon "rocket" "" face label -0.0575)
|
|
|
|
" "))
|
|
|
|
(add-to-list 'global-mode-string
|
|
|
|
'(t (:eval lsp-modeline-icon))
|
|
|
|
'append))))))
|
2020-05-28 11:03:49 +02:00
|
|
|
|
|
|
|
|
|
|
|
(use-package! lsp-ui
|
2021-05-16 21:17:16 -04:00
|
|
|
:hook (lsp-mode . lsp-ui-mode)
|
2021-05-18 01:05:35 -04:00
|
|
|
:init
|
|
|
|
(defadvice! +lsp--use-hook-instead-a (orig-fn &rest args)
|
|
|
|
"Change `lsp--auto-configure' to not force `lsp-ui-mode' on us. Using a hook
|
|
|
|
instead is more sensible."
|
|
|
|
:around #'lsp--auto-configure
|
|
|
|
(letf! ((#'lsp-ui-mode #'ignore))
|
|
|
|
(apply orig-fn args)))
|
|
|
|
|
2020-05-28 11:03:49 +02:00
|
|
|
:config
|
2021-05-16 21:17:16 -04:00
|
|
|
(when (featurep! +peek)
|
|
|
|
(set-lookup-handlers! 'lsp-ui-mode
|
|
|
|
:definition 'lsp-ui-peek-find-definitions
|
|
|
|
:implementations 'lsp-ui-peek-find-implementation
|
2021-05-20 20:29:08 +02:00
|
|
|
:references 'lsp-ui-peek-find-references
|
|
|
|
:async t))
|
2021-05-16 21:17:16 -04:00
|
|
|
|
2021-05-18 00:05:15 -04:00
|
|
|
(setq lsp-ui-peek-enable (featurep! +peek)
|
|
|
|
lsp-ui-doc-max-height 8
|
2020-05-28 11:03:49 +02:00
|
|
|
lsp-ui-doc-max-width 35
|
2020-10-14 18:38:09 -04:00
|
|
|
lsp-ui-doc-show-with-mouse nil ; don't disappear on mouseover
|
|
|
|
lsp-ui-doc-position 'at-point
|
2021-05-16 21:17:16 -04:00
|
|
|
lsp-ui-sideline-ignore-duplicate t
|
2020-05-28 11:03:49 +02:00
|
|
|
;; Don't show symbol definitions in the sideline. They are pretty noisy,
|
|
|
|
;; and there is a bug preventing Flycheck errors from being shown (the
|
|
|
|
;; errors flash briefly and then disappear).
|
2021-02-25 13:44:58 -05:00
|
|
|
lsp-ui-sideline-show-hover nil
|
Drop Emacs 26.x support
Emacs 27.x has been the stable version of Emacs for nearly a year, and
introduces a litany of bugfixes, performance, and quality-of-life
improvements that significantly reduce Doom's maintenance burden (like
XDG support, early-init.el, image manipulation without imagemagick, a
native JSON library, harfbuzz support, pdumper, and others).
With so many big changes on Doom's horizon, I like having one less (big)
thing to worry about.
Also reverts bb677cf7a (#5232) as it is no longer needed.
2021-07-06 01:54:32 -04:00
|
|
|
;; Re-enable icon scaling (it's disabled by default upstream for Emacs
|
|
|
|
;; 26.x compatibility; see emacs-lsp/lsp-ui#573)
|
2021-07-06 13:46:53 -05:00
|
|
|
lsp-ui-sideline-actions-icon lsp-ui-sideline-actions-icon-default
|
2021-05-23 21:50:57 -04:00
|
|
|
;; REVIEW Temporarily disabled, due to immense slowness on every
|
|
|
|
;; keypress. See emacs-lsp/lsp-ui#613
|
|
|
|
lsp-ui-doc-enable nil)
|
2020-05-28 11:03:49 +02:00
|
|
|
|
2020-10-14 18:36:06 -04:00
|
|
|
(map! :map lsp-ui-peek-mode-map
|
|
|
|
"j" #'lsp-ui-peek--select-next
|
|
|
|
"k" #'lsp-ui-peek--select-prev
|
|
|
|
"C-k" #'lsp-ui-peek--select-prev-file
|
2021-05-16 21:17:16 -04:00
|
|
|
"C-j" #'lsp-ui-peek--select-next-file))
|
2020-05-28 11:03:49 +02:00
|
|
|
|
|
|
|
|
|
|
|
(use-package! helm-lsp
|
|
|
|
:when (featurep! :completion helm)
|
|
|
|
:commands helm-lsp-workspace-symbol helm-lsp-global-workspace-symbol)
|
|
|
|
|
|
|
|
|
|
|
|
(use-package! lsp-ivy
|
|
|
|
:when (featurep! :completion ivy)
|
|
|
|
:commands lsp-ivy-workspace-symbol lsp-ivy-global-workspace-symbol)
|