aboutsummaryrefslogtreecommitdiff
path: root/modules/prog-lsp.el
blob: 045dda248d14162bcd422606e263225c94c8e6a0 (plain)
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
;;; prog-lsp --- Setup for LSP Mode -*- lexical-binding: t; coding: utf-8; -*-
;; author: Craig Jennings <c@cjennings.net>

;;; Commentary:

;; good reference as to what to enable/disable in lsp-mode
;; https://emacs-lsp.github.io/lsp-mode/tutorials/how-to-turn-off/

;;; Code:

;; Forward declarations for byte-compile and let-binding under lexical scope.
;; Real definitions are lsp-mode's defcustoms.
(defvar eldoc-documentation-functions)
(defvar lsp-file-watch-ignored-directories)
(defvar lsp-enable-remote)

(declare-function lsp-eldoc-function "lsp-mode")

;;;;; --------------------- File-Watch Ignore Patterns ---------------------
;; lsp-mode prompts when a workspace exceeds `lsp-file-watch-threshold' (1000)
;; directories.  Real source repos cross that line easily once node_modules,
;; build outputs, and language caches are counted.  These patterns extend the
;; lsp-mode defaults (.git, .svn, .idea, ...) instead of replacing them, so the
;; built-in VC/IDE excludes still apply.  Buffer-local overrides via
;; `.dir-locals.el' don't work — lsp-mode reads the global value at workspace
;; init, not the buffer-local one.  Hence: global defaults here.

(defvar cj/lsp-file-watch-ignored-extras
  '("[/\\\\]node_modules\\'"
    "[/\\\\]\\.ruff_cache\\'"
    "[/\\\\]dist\\'"
    "[/\\\\]coverage\\'"
    "[/\\\\]test-results\\'"
    "[/\\\\]playwright-report\\'"
    "[/\\\\]tf[/\\\\]\\.terraform\\'"
    "[/\\\\]__pycache__\\'"
    "[/\\\\]\\.venv\\'"
    "[/\\\\]venv\\'"
    "[/\\\\]\\.pytest_cache\\'"
    "[/\\\\]\\.mypy_cache\\'"
    "[/\\\\]target\\'")
  "Build/cache directory patterns to add to `lsp-file-watch-ignored-directories'.
Each entry is an Emacs regex matching a path ending in the named directory.")

(defun cj/lsp--add-file-watch-ignored-extras ()
  "Append `cj/lsp-file-watch-ignored-extras' to lsp-mode's ignore list.
Idempotent — `add-to-list' skips patterns already present."
  (dolist (pattern cj/lsp-file-watch-ignored-extras)
    (add-to-list 'lsp-file-watch-ignored-directories pattern)))

(defun cj/lsp--remove-eldoc-provider-global ()
  "Remove lsp-mode's provider from the global `eldoc-documentation-functions'.
Run once after lsp-mode loads.  The previous per-buffer removal raced
lsp's own buffer-local add: the buffer-local remove fired before lsp
populated the buffer-local hook (lsp inherits the global default and
mutates from there), so the buffer-local hook ended up holding the
provider anyway.  Removing globally before lsp ever attaches a buffer
makes the absence stick for every subsequent lsp-managed buffer."
  (remove-hook 'eldoc-documentation-functions #'lsp-eldoc-function))

;;;;; ---------------------------- LSP Mode ---------------------------

(use-package lsp-mode
  :hook
  ((c-mode c++-mode go-mode js-mode js-jsx-mode typescript-mode python-mode web-mode) . lsp-deferred)
  :commands (lsp)
  :bind (:map lsp-mode-map
              ("C-c d" . lsp-describe-thing-at-point)
              ("C-c a" . lsp-execute-code-action))
  :bind-keymap ("C-c L" . lsp-command-map)
  :init
  (setq lsp-enable-remote nil) ;; Don't start LSP on TRAMP files (slow, prompts for project root)
  :config
  (setq lsp-auto-guess-root t)
  (setq lsp-log-io nil)
  (setq lsp-restart 'auto-restart)
  (setq lsp-enable-symbol-highlighting nil)
  (setq lsp-enable-on-type-formatting nil)
  (setq lsp-signature-auto-activate nil)
  (setq lsp-signature-render-documentation nil)
  ;; Strip lsp-mode's eldoc provider from the GLOBAL hook value once,
  ;; not per buffer.  See `cj/lsp--remove-eldoc-provider-global' for
  ;; why per-buffer racing didn't stick.
  (cj/lsp--remove-eldoc-provider-global)
  (setq lsp-modeline-code-actions-enable nil)
  (setq lsp-modeline-diagnostics-enable nil)
  (setq lsp-headerline-breadcrumb-enable nil)
  (setq lsp-semantic-tokens-enable nil)
  (setq lsp-enable-folding nil)
  (setq lsp-enable-imenu nil)
  (setq lsp-enable-snippet nil)
  (setq read-process-output-max (* 1024 1024)) ;; 1MB
  (setq lsp-idle-delay 0.5)
  (cj/lsp--add-file-watch-ignored-extras))

;;;;; ----------------------------- LSP UI ----------------------------

(use-package lsp-ui
  :after lsp-mode
  :commands lsp-ui-mode
  :config
  (setq lsp-ui-doc-enable nil)
  (setq lsp-ui-doc-header t)
  (setq lsp-ui-doc-include-signature t)
  (setq lsp-ui-doc-border (face-foreground 'default))
  (setq lsp-ui-sideline-show-code-actions nil) ;; turn off code actions in sidebar
  (setq lsp-ui-sideline-delay 0.05))

(provide 'prog-lsp)
;;; prog-lsp.el ends here