Bug#927749: elpa-lsp-mode: Race condition in lsp-mode when using imenu and session restore
Package: elpa-lsp-mode
Version: 6.0-1
Severity: normal
Tags: patch
There is a race condition possibly leading to an error when lsp-mode is used
with imenu and session restore. See the upstream bug report for more details:
https://github.com/emacs-lsp/lsp-mode/issues/784
The author helped in getting a patch for version 6.0 as included in Debian
Buster. The packet lsp-ui also need a small patch, I'll file another bug for
that.
-- System Information:
Debian Release: buster/sid
APT prefers testing
APT policy: (990, 'testing'), (50, 'unstable')
Architecture: amd64 (x86_64)
Foreign Architectures: i386
Kernel: Linux 4.19.0-4-amd64 (SMP w/8 CPU cores)
Kernel taint flags: TAINT_OOT_MODULE, TAINT_UNSIGNED_MODULE
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8), LANGUAGE=en_US:us (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled
Versions of packages elpa-lsp-mode depends on:
ii elpa-dash 2.14.1+dfsg-1
ii elpa-dash-functional 1.2.0+dfsg-5
ii elpa-f 0.20.0-1
ii elpa-ht 2.2-2
ii elpa-spinner 1.7.3-1
ii emacsen-common 3.0.4
Versions of packages elpa-lsp-mode recommends:
ii emacs 1:26.1+1-3.2
ii emacs-gtk [emacs] 1:26.1+1-3.2
elpa-lsp-mode suggests no packages.
-- no debconf information
--- lsp-mode.el.orig 2019-01-21 21:56:43.000000000 +0100
+++ lsp-mode.el 2019-04-22 19:17:56.714357377 +0200
@@ -473,6 +473,16 @@
(defvar lsp--tcp-port 10000)
+(defvar-local lsp--document-symbols nil
+ "The latest document symbols.")
+
+(defvar-local lsp--document-symbols-request-async nil
+ "If non-nil, request document symbols asynchronously.")
+
+(defvar-local lsp--document-symbols-tick -1
+ "The value of `buffer-chars-modified-tick' when document
+ symbols were last retrieved.")
+
(cl-defgeneric lsp-execute-command (server command arguments)
"Ask SERVER to execute COMMAND with ARGUMENTS.")
@@ -1674,6 +1684,9 @@
(kind (if (hash-table-p sync) (gethash "change" sync) sync)))
(setq lsp--server-sync-method (or lsp-document-sync-method
(alist-get kind lsp--sync-methods))))
+ (when (and lsp-auto-configure (lsp--capability "documentSymbolProvider"))
+ (lsp-enable-imenu))
+
(run-hooks 'lsp-after-open-hook))
(define-inline lsp--text-document-identifier ()
@@ -2591,8 +2604,38 @@
'def-params td-params)))
(defun lsp--get-document-symbols ()
- (lsp-request "textDocument/documentSymbol"
- `(:textDocument ,(lsp--text-document-identifier))))
+ "Get document symbols.
+
+If the buffer has not been modified since symbols were last
+retrieved, simply return the latest result.
+
+Else, if the request was initiated by Imenu updating its menu-bar
+entry, perform it asynchronously; i.e., give Imenu the latest
+result and then force a refresh when a new one is available.
+
+Else (e.g., due to intereactive use of `imenu' or `xref'),
+perform the request synchronously."
+ (if (= (buffer-chars-modified-tick) lsp--document-symbols-tick)
+ lsp--document-symbols
+ (let ((method "textDocument/documentSymbol")
+ (params `(:textDocument ,(lsp--text-document-identifier)))
+ (tick (buffer-chars-modified-tick)))
+ (if (not lsp--document-symbols-request-async)
+ (prog1
+ (setq lsp--document-symbols (lsp-request method params))
+ (setq lsp--document-symbols-tick tick))
+ (lsp-request-async method params
+ (lambda (document-symbols)
+ (setq lsp--document-symbols document-symbols
+ lsp--document-symbols-tick tick)
+ (lsp--imenu-refresh))
+ :mode 'alive)
+ lsp--document-symbols))))
+
+(advice-add 'imenu-update-menubar :around
+ (lambda (oldfun &rest r)
+ (let ((lsp--document-symbols-request-async t))
+ (apply oldfun r))))
(defun lsp--xref-backend () 'xref-lsp)
@@ -3173,9 +3216,14 @@
(result (compare-strings name1 0 (length name1) name2 0 (length name2))))
(if (numberp result) result 0)))
+(defun lsp--imenu-refresh ()
+ "Force Imenu to refresh itself."
+ (imenu--menubar-select imenu--rescan-item))
+
(defun lsp-enable-imenu ()
"Use lsp-imenu for the current buffer."
- (setq-local imenu-create-index-function #'lsp--imenu-create-index))
+ (setq-local imenu-create-index-function #'lsp--imenu-create-index)
+ (lsp--imenu-refresh))
(defun lsp-resolve-final-function (command)
"Resolve final function COMMAND."
@@ -3304,8 +3352,6 @@
(lsp-ui-flycheck-enable t)
(flycheck-mode 1)))
- (lsp-enable-imenu)
-
(when (functionp 'company-lsp)
(company-mode 1)
(setq-local company-backends '(company-lsp))
Reply to: