diff options
| -rw-r--r-- | lisp/progmodes/eglot.el | 79 |
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. | |||
| 2238 | VERSION is the LSP Document version reported for DIAGNOSTICS (comparable | 2239 | VERSION is the LSP Document version reported for DIAGNOSTICS (comparable |
| 2239 | to `eglot--docver') or nil if server didn't bother.") | 2240 | to `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. | ||
| 2244 | MAP and PREV-MAP are alists of (TOKEN . DIAGS) entries. DIAGS is a | ||
| 2245 | sequence of LSP/Flymake diagnostics objects. TOKEN identifies the | ||
| 2246 | source of a partial report. VERSION is the LSP Document version | ||
| 2247 | reported for diagnostics in MAP. PREV-MAP contains the diagnostics of | ||
| 2248 | the 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. |
| 3191 | REGION is the (BEG . END) region the diagnostics pertina to. VERSION is | 3253 | VERSION is the document version number. REGION is the (BEG . END) |
| 3192 | the document version number." | 3254 | pertaining 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 | ||