forked from doomemacs/doomemacs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
config.el
235 lines (209 loc) · 9.81 KB
/
config.el
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
;;; tools/lsp/config.el -*- lexical-binding: t; -*-
(defvar +lsp-defer-shutdown 3
"If non-nil, defer shutdown of LSP servers for this many seconds after last
workspace buffer is closed.
This delay prevents premature server shutdown when a user still intends on
working on that project after closing the last buffer.")
;; TODO : set eglot-events-buffer-size to nil in doom-debug-mode
;;
;;; Packages
(use-package! eglot
:when (featurep! +eglot)
:init
(setq eglot-sync-connect 1
eglot-connect-timeout 10
eglot-autoshutdown t
eglot-send-changes-idle-time 0.5
;; NOTE: Do NOT set eglot-auto-display-help-buffer to t.
;; With popup-rule! :select t, eglot will steal focus from the source code very often.
eglot-auto-display-help-buffer nil)
:config
(set-popup-rule! "^\\*eglot-help" :size 0.35 :quit t :select t)
(when (featurep! :checkers syntax)
;; Eager loading which is okay-ish since we want eglot to feed flycheck as soon as possible.
(load! "flycheck-eglot.el")
(require 'flycheck-eglot))
(set-lookup-handlers! 'eglot--managed-mode
:documentation #'+eglot/documentation-lookup-handler
:definition '(xref-find-definitions :async t)
:references '(xref-find-references :async t)))
(use-package! lsp-mode
:unless (featurep! +eglot)
:commands lsp-install-server
:init
(setq lsp-session-file (concat doom-etc-dir "lsp-session"))
;; Do not prompt the user for the project root every time we open a new
;; lsp-worthy file, instead, try to guess it with projectile.
(setq lsp-auto-guess-root t)
;; Auto-kill LSP server after last workspace buffer is killed.
(setq lsp-keep-workspace-alive nil)
;; Let `flycheck-check-syntax-automatically' determine this.
(setq lsp-flycheck-live-reporting nil)
;; For `lsp-clients'
(setq lsp-server-install-dir (concat doom-etc-dir "lsp/")
lsp-intelephense-storage-path (concat doom-cache-dir "lsp-intelephense/"))
(when (featurep! :config default +bindings)
;; Let doom bind the lsp keymap.
(setq lsp-keymap-prefix nil))
;; Disable LSP's superfluous, expensive and/or debatably unnecessary features.
;; Some servers implement these poorly. Better to just rely on Emacs' native
;; mechanisms and make these opt-in.
(setq lsp-enable-folding nil
;; HACK Fix #2911, until it is resolved upstream. Links come in
;; asynchronously from the server, but lsp makes no effort to
;; "select" the original buffer before laying them down, so they
;; could be rendered in the wrong buffer (like the minibuffer).
lsp-enable-links nil
;; Potentially slow
lsp-enable-file-watchers nil
lsp-enable-text-document-color nil
lsp-enable-semantic-highlighting nil
;; Don't modify our code without our permission
lsp-enable-indentation nil
lsp-enable-on-type-formatting nil
;; capf is the preferred completion mechanism for lsp-mode now
lsp-prefer-capf t)
:config
(set-popup-rule! "^\\*lsp-help" :size 0.35 :quit t :select t)
(set-lookup-handlers! 'lsp-mode :async t
:documentation #'lsp-describe-thing-at-point
:definition #'lsp-find-definition
:implementations #'lsp-find-implementation
:type-definition #'lsp-find-type-definition
:references #'lsp-find-references)
;; TODO Lazy load these. They don't need to be loaded all at once unless the
;; user uses `lsp-install-server'.
(when lsp-auto-configure
(mapc (lambda (package) (require package nil t))
lsp-client-packages))
(defadvice! +lsp-init-a (&optional arg)
"Enable `lsp-mode' in the current buffer.
Meant to gimp `lsp', which is too eager about installing LSP servers, or
prompting to do so, or complaining about no LSP servers, or initializing
lsp-ui-mode, company, yasnippet and flycheck. We want LSP to work only if the
server is present, and for server installation to be a deliberate act by the
end-user. Also, setting up these other packages are handled by their respective
modules.
Also see:
+ `+lsp-init-company-h' (on `lsp-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
(interactive "P")
(and (buffer-file-name (buffer-base-buffer))
(require 'lsp-mode nil t)
(setq-local
lsp--buffer-workspaces
(or (lsp--try-open-in-library-workspace)
(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
(or (not (boundp 'read-process-output-max))
(setq-local read-process-output-max (* 1024 1024)))
;; REVIEW LSP causes a lot of allocations, with or without Emacs 27+'s
;; native JSON library, so we up the GC threshold to stave off
;; GC-induced slowdowns/freezes.
(setq-local gcmh-high-cons-threshold (* 2 gcmh-high-cons-threshold))
(prog1 (lsp-mode 1)
(setq-local lsp-buffer-uri (lsp--buffer-uri))
;; Announce what project root we're using, for diagnostic purposes
(if-let (root (lsp--calculate-root (lsp-session) (buffer-file-name)))
(lsp--info "Guessed project root is %s" (abbreviate-file-name root))
(lsp--info "Could not guess project root."))
(lsp--info "Connected to %s."
(apply #'concat
(mapcar
(lambda (it) (format "[%s]" (lsp--workspace-print it)))
lsp--buffer-workspaces))))))
(when (featurep! :config default +bindings)
(dolist (leader-key (list doom-leader-key doom-leader-alt-key))
(let ((lsp-keymap-prefix (concat leader-key " c l")))
(lsp-enable-which-key-integration))))
(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)
;; Ensure `company-capf' is at the front of `company-backends'
(setq-local company-backends
(cons 'company-capf
(remq 'company-capf company-backends)))
(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'."
(pcase lsp-diagnostic-package
((or :auto 'nil) ; try flycheck, fall back to flymake
(let ((lsp-diagnostic-package
(if (require 'flycheck nil t) :flycheck :flymake)))
(+lsp-init-flycheck-or-flymake-h)))
((or :flymake 't)
(lsp--flymake-setup))
(:flycheck
(let ((old-checker flycheck-checker))
(lsp-flycheck-enable)
;; Ensure file/dir local `flycheck-checker' is respected
(when old-checker
(setq-local flycheck-checker old-checker)
(kill-local-variable 'flycheck-check-syntax-automatically)))))))
(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
auto-killed (which is a potentially expensive process)."
:around #'lsp--shutdown-workspace
(if (or lsp-keep-workspace-alive
restart
(null +lsp-defer-shutdown)
(= +lsp-defer-shutdown 0))
(funcall orig-fn restart)
(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)
(let ((lsp--cur-workspace workspace))
(unless (lsp--workspace-buffers lsp--cur-workspace)
(funcall orig-fn))))
lsp--cur-workspace))))
(defadvice! +lsp-prompt-if-no-project-a (session file-name)
"Prompt for the project root only if no project was found."
:after-until #'lsp--calculate-root
(cond ((not lsp-auto-guess-root)
nil)
((cl-find-if (lambda (dir)
(and (lsp--files-same-host dir file-name)
(file-in-directory-p file-name dir)))
(lsp-session-folders-blacklist session))
nil)
((lsp--find-root-interactively session))))
;; Don't prompt to restart LSP servers while quitting Emacs
(add-hook! 'kill-emacs-hook (setq lsp-restart 'ignore)))
(use-package! lsp-ui
:unless (featurep! +eglot)
:hook (lsp-mode . lsp-ui-mode)
:config
(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
;; `+lookup/documentation'
lsp-ui-doc-enable nil
;; 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).
lsp-ui-sideline-show-hover nil)
(when (featurep! +peek)
(set-lookup-handlers! 'lsp-ui-mode :async t
:definition 'lsp-ui-peek-find-definitions
:implementations 'lsp-ui-peek-find-implementation
:references 'lsp-ui-peek-find-references)))
(use-package! helm-lsp
:unless (featurep! +eglot)
:when (featurep! :completion helm)
:commands helm-lsp-workspace-symbol helm-lsp-global-workspace-symbol)
(use-package! lsp-ivy
:unless (featurep! +eglot)
:when (featurep! :completion ivy)
:commands lsp-ivy-workspace-symbol lsp-ivy-global-workspace-symbol)