How to speed up lsp-mode

  |   Source

Here is my setup,

(with-eval-after-load "lsp-mode"
  ;; enable log only for debug
  (setq lsp-log-io nil)

  ;; use `evil-matchit' instead
  (setq lsp-enable-folding nil)

  ;; no real time syntax check
  (setq lsp-diagnostic-package :none)

  ;; handle yasnippet by myself
  (setq lsp-enable-snippet nil)

  ;; use `company-ctags' only.
  ;; Please note `company-lsp' is automatically enabled if installed
  (setq lsp-enable-completion-at-point nil)

  ;; turn off for better performance
  (setq lsp-enable-symbol-highlighting nil)

  ;; use ffip instead
  (setq lsp-enable-links nil)

  ;; auto restart lsp
  (setq lsp-restart 'auto-restart)

  ;; @see https://github.com/emacs-lsp/lsp-mode/pull/1498 and code related to auto configure.
  ;; Require clients could be slow.
  ;; I only load `lsp-clients' because it includes the js client which I'm interested
  (setq lsp-client-packages '(lsp-clients))

  ;; don't scan 3rd party javascript libraries
  (push "[/\\\\][^/\\\\]*\\.\\(json\\|html\\|jade\\)$" lsp-file-watch-ignored) ; json

  ;; don't ping LSP lanaguage server too frequently
  (defvar lsp-on-touch-time 0)
  (defadvice lsp-on-change (around lsp-on-change-hack activate)
    ;; don't run `lsp-on-change' too frequently
    (when (> (- (float-time (current-time))
                lsp-on-touch-time) 30) ;; 30 seconds
      (setq lsp-on-touch-time (float-time (current-time)))
      ad-do-it)))

(defun my-connect-lsp (&optional no-reconnect)
  "Connect lsp server.  If NO-RECONNECT is t, don't shutdown existing lsp connection."
  (interactive "P")
  (when (and (not no-reconnect)
             (fboundp 'lsp-disconnect))
    (lsp-disconnect))
  (when (and buffer-file-name
             (not (member (file-name-extension buffer-file-name)
                          '("json"))))
    (unless (and (boundp 'lsp-mode) lsp-mode)
      (if (derived-mode-p 'js2-mode) (setq-local lsp-enable-imenu nil))
      (lsp-deferred))))

To enable lsp for the major mode XXX-mode needs only one line,

(add-hook 'XXX-mode-hook #'my-connect-lsp)

You also need install three packages,

Explanation,

Ctags is used to generate tags file for company-ctags and counsel-etags. GNU Find is required for find-file-in-project.

These three packages are faster and can replace the corresponding functionalities in lsp-mode.

I don't need any lint tools from lsp-mode because the lint tool is already included in our build script. I can see the syntax error from terminal.

I advice the lsp-on-change in order to notify the language server less frequently.

js2-mode has its own javascript parser extract imenu items. So I don't need javascript language server's parser to send back imenu items.

By default lsp-client-packages contains many clients, but I only code in javascript which is included in lsp-clients.

Here is code quoted from lsp-mode,

;;;###autoload
(defun lsp (&optional arg)
  ;; ...
  (when (and lsp-auto-configure)
    (seq-do (lambda (package) (require package nil t))
            lsp-client-packages))
  ;; ...
)

I have done some profiling by insert (profiler-report-cpu) at the end of lsp (the bottlenecks is highlighted).

lsp-mode-bottleneck-nq8.png

The language server I used can read jsconfig.json in project root. I can specify the directories to exclude in it.

Comments powered by Disqus