aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/progmodes/eglot.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/progmodes/eglot.el')
-rw-r--r--lisp/progmodes/eglot.el79
1 files changed, 75 insertions, 4 deletions
diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el
index a4440235cbe..f7d38d8e417 100644
--- a/lisp/progmodes/eglot.el
+++ b/lisp/progmodes/eglot.el
@@ -1151,7 +1151,8 @@ object."
1151 :tagSupport 1151 :tagSupport
1152 `(:valueSet 1152 `(:valueSet
1153 [,@(mapcar 1153 [,@(mapcar
1154 #'car eglot--tag-faces)]))) 1154 #'car eglot--tag-faces)]))
1155 :$streamingDiagnostics `(:dynamicRegistration :json-false))
1155 :window `(:showDocument (:support t) 1156 :window `(:showDocument (:support t)
1156 :showMessage (:messageActionItem 1157 :showMessage (:messageActionItem
1157 (:additionalPropertiesSupport t)) 1158 (:additionalPropertiesSupport t))
@@ -2238,6 +2239,14 @@ DIAGNOSTICS is a sequence of LSP or Flymake diagnostics objects.
2238VERSION is the LSP Document version reported for DIAGNOSTICS (comparable 2239VERSION is the LSP Document version reported for DIAGNOSTICS (comparable
2239to `eglot--docver') or nil if server didn't bother.") 2240to `eglot--docver') or nil if server didn't bother.")
2240 2241
2242(defvar-local eglot--streamed-diagnostics nil
2243 "A (VERSION MAP PREV-MAP) description of \"streamed\" diagnostics.
2244MAP and PREV-MAP are alists of (TOKEN . DIAGS) entries. DIAGS is a
2245sequence of LSP/Flymake diagnostics objects. TOKEN identifies the
2246source of a partial report. VERSION is the LSP Document version
2247reported for diagnostics in MAP. PREV-MAP contains the diagnostics of
2248the previous reports for TOKEN.")
2249
2241(defvar-local eglot--suggestion-overlay (make-overlay 0 0) 2250(defvar-local eglot--suggestion-overlay (make-overlay 0 0)
2242 "Overlay for `eglot-code-action-suggestion'.") 2251 "Overlay for `eglot-code-action-suggestion'.")
2243 2252
@@ -3179,6 +3188,59 @@ version the diagnostics pertain to."
3179 ;; starts on idle-timer (github#957) 3188 ;; starts on idle-timer (github#957)
3180 (eglot--flymake-report-push+pulled))))) 3189 (eglot--flymake-report-push+pulled)))))
3181 3190
3191(cl-defmethod eglot-handle-notification
3192 (server (_method (eql $/streamDiagnostics))
3193 &key uri diagnostics version token kind
3194 &allow-other-keys)
3195 "Handle notification $/streamDiagnostics."
3196 (cl-macrolet ((report (what mode)
3197 `(eglot--flymake-report-1 ,what ,mode)))
3198 (eglot--flymake-handle-push
3199 server uri diagnostics version
3200 (lambda (lsp-diags)
3201 (cl-symbol-macrolet ((map (cadr eglot--streamed-diagnostics)))
3202 (let* ((doc-v eglot--docver)
3203 (known-v (car eglot--streamed-diagnostics))
3204 (prev-map (caddr eglot--streamed-diagnostics))
3205 (diags (if (equal kind "unchanged")
3206 (cdr (assoc token (if (eq known-v doc-v)
3207 map prev-map)))
3208 lsp-diags))
3209 probe)
3210 ;; (trace-values (buffer-name) "lsp-diags" (length lsp-diags)
3211 ;; "diags" (length diags) "kind" kind
3212 ;; "known-v" known-v "doc-v" doc-v)
3213 (cond ((and known-v (< doc-v known-v))
3214 ;; Ignore out of date (shouldn't happen)
3215 (report nil :stay))
3216 ((or (null known-v) (> doc-v known-v))
3217 ;; `doc-v' is greater than (potentially nil)
3218 ;; recorded `known-v'. Save old known-v and map,
3219 ;; "inaugurate" new doc-v, report this initial subset,
3220 ;; clearing all existing diagnostics.
3221 (cl-loop for (tk . diags) in map
3222 do (setf (alist-get tk prev-map nil nil #'equal) diags))
3223 (let ((entry (cons token diags)))
3224 (setq eglot--streamed-diagnostics
3225 `(,doc-v (,entry) ,prev-map))
3226 (report (cdr entry) :clear)))
3227 ((setq probe (assoc token map))
3228 ;; `diags' are an update to an existing report for
3229 ;; this token, for this `doc-v' Record and report
3230 ;; all to Flymake, clearing all existing diagnostics.
3231 (setcdr probe diags)
3232 (cl-loop for e in map
3233 for m = :clear then :stay
3234 do (report (cdr e) m)))
3235 (t
3236 ;; It's the first time we hear about `token' for this
3237 ;; already inaugurated `doc-v' add its diagnostics to
3238 ;; the map, and report only this subset, not clearing
3239 ;; any old diagnostics.
3240 (let ((entry (cons token diags)))
3241 (push entry map)
3242 (report (cdr entry) :stay))))))))))
3243
3182(defun eglot--flymake-diag-type (severity) 3244(defun eglot--flymake-diag-type (severity)
3183 "Convert LSP diagnostic SEVERITY to Eglot/Flymake diagnostic type." 3245 "Convert LSP diagnostic SEVERITY to Eglot/Flymake diagnostic type."
3184 (cond ((null severity) 'eglot-error) 3246 (cond ((null severity) 'eglot-error)
@@ -3188,8 +3250,8 @@ version the diagnostics pertain to."
3188 3250
3189(defun eglot--flymake-make-diag (diag-spec version region) 3251(defun eglot--flymake-make-diag (diag-spec version region)
3190 "Convert LSP diagnostic DIAG-SPEC to Flymake diagnostic. 3252 "Convert LSP diagnostic DIAG-SPEC to Flymake diagnostic.
3191REGION is the (BEG . END) region the diagnostics pertina to. VERSION is 3253VERSION is the document version number. REGION is the (BEG . END)
3192the document version number." 3254pertaining to DIAG-SPEC."
3193 (eglot--dbind ((Diagnostic) range code message severity source tags) 3255 (eglot--dbind ((Diagnostic) range code message severity source tags)
3194 diag-spec 3256 diag-spec
3195 (pcase-let 3257 (pcase-let
@@ -3234,6 +3296,14 @@ may be called multiple times (respecting the protocol of
3234 ;; Use pull diagnostics if server supports it 3296 ;; Use pull diagnostics if server supports it
3235 ((eglot-server-capable :diagnosticProvider) 3297 ((eglot-server-capable :diagnosticProvider)
3236 (eglot--flymake-pull)) 3298 (eglot--flymake-pull))
3299 ((eglot-server-capable :$streamingDiagnosticsProvider)
3300 (let ((v (car eglot--streamed-diagnostics))
3301 (map (cadr eglot--streamed-diagnostics)))
3302 (if (and v (< v eglot--docver))
3303 (eglot--flymake-report-2 nil :stay)
3304 (cl-loop for e in map
3305 for m = :clear then :stay
3306 do (eglot--flymake-report-1 (cdr e) m)))))
3237 ;; Otherwise push whatever we might have, and wait for 3307 ;; Otherwise push whatever we might have, and wait for
3238 ;; further `textDocument/publishDiagnostics'. 3308 ;; further `textDocument/publishDiagnostics'.
3239 (t (eglot--flymake-report-push+pulled :force t)))) 3309 (t (eglot--flymake-report-push+pulled :force t))))
@@ -3318,7 +3388,8 @@ When response arrives call registered `eglot--flymake-report-fn'."
3318 3388
3319(defun eglot--flymake-reset () 3389(defun eglot--flymake-reset ()
3320 (setq eglot--pulled-diagnostics nil 3390 (setq eglot--pulled-diagnostics nil
3321 eglot--pushed-diagnostics nil) 3391 eglot--pushed-diagnostics nil
3392 eglot--streamed-diagnostics nil)
3322 (when eglot--flymake-report-fn 3393 (when eglot--flymake-report-fn
3323 (eglot--flymake-report-1 nil :clear :force t))) 3394 (eglot--flymake-report-1 nil :clear :force t)))
3324 3395