From 77d3487af48a72cd836fa3742229cb95649c32b7 Mon Sep 17 00:00:00 2001 From: Ruin0x11 Date: Wed, 27 Dec 2023 23:00:14 -0600 Subject: [PATCH 1/3] Basic pull diagnostics support --- lsp-mode.el | 65 +++++++++++++++++++++++++++++++++++++++---------- lsp-protocol.el | 5 ++++ 2 files changed, 57 insertions(+), 13 deletions(-) diff --git a/lsp-mode.el b/lsp-mode.el index 38ea0b6165..fcee996256 100644 --- a/lsp-mode.el +++ b/lsp-mode.el @@ -1035,6 +1035,7 @@ directory") ("textDocument/signatureHelp" :capability :signatureHelpProvider) ("textDocument/typeDefinition" :capability :typeDefinitionProvider) ("textDocument/typeHierarchy" :capability :typeHierarchyProvider) + ("textDocument/diagnostic" :capability :diagnosticProvider) ("workspace/executeCommand" :capability :executeCommandProvider) ("workspace/symbol" :capability :workspaceSymbolProvider)) @@ -2299,6 +2300,17 @@ Common usecase are: The result format is vector [_ errors warnings infos hints] or nil." (gethash (lsp--fix-path-casing path) lsp-diagnostic-stats)) +(defun lsp-diagnostics--request-pull-diagnostics (workspace) + "Request new diagnostics for the current file within WORKSPACE. +This is only executed if the server supports pull diagnostics." + (when (lsp-feature? "textDocument/diagnostic") + (let ((path (lsp--fix-path-casing (buffer-file-name)))) + (lsp-request-async "textDocument/diagnostic" + (list :textDocument (lsp--text-document-identifier)) + (-lambda ((&DocumentDiagnosticReport :kind :items?)) + (lsp-diagnostics--apply-pull-diagnostics workspace path kind items?)) + :mode 'tick)))) + (defun lsp-diagnostics--update-path (path new-stats) (let ((new-stats (copy-sequence new-stats)) (path (lsp--fix-path-casing (directory-file-name path)))) @@ -2308,9 +2320,8 @@ The result format is vector [_ errors warnings infos hints] or nil." (aref new-stats idx))) (puthash path new-stats lsp-diagnostic-stats)))) -(lsp-defun lsp--on-diagnostics-update-stats (workspace - (&PublishDiagnosticsParams :uri :diagnostics)) - (let ((path (lsp--fix-path-casing (lsp--uri-to-path uri))) +(defun lsp-diagnostics--convert-and-update-path-stats (workspace path diagnostics) + (let ((path (lsp--fix-path-casing path)) (new-stats (make-vector 5 0))) (mapc (-lambda ((&Diagnostic :severity?)) (cl-incf (aref new-stats (or severity? 1)))) @@ -2324,6 +2335,27 @@ The result format is vector [_ errors warnings infos hints] or nil." (directory-file-name path))))) (lsp-diagnostics--update-path path new-stats)))) +(lsp-defun lsp--on-diagnostics-update-stats (workspace + (&PublishDiagnosticsParams :uri :diagnostics)) + (lsp-diagnostics--convert-and-update-path-stats workspace (lsp--uri-to-path uri) diagnostics)) + +(defun lsp-diagnostics--apply-pull-diagnostics (workspace path kind diagnostics?) + "Update WORKSPACE diagnostics at PATH with DIAGNOSTICS?. +Depends on KIND being a \\='full\\=' update." + (cond + ((equal kind "full") + ;; TODO support `lsp-diagnostic-filter' + ;; (the params types differ from the published diagnostics response) + (lsp-diagnostics--convert-and-update-path-stats workspace path diagnostics?) + (-let* ((lsp--virtual-buffer-mappings (ht)) + (workspace-diagnostics (lsp--workspace-diagnostics workspace))) + (if (seq-empty-p diagnostics?) + (remhash path workspace-diagnostics) + (puthash path (append diagnostics? nil) workspace-diagnostics)) + (run-hooks 'lsp-diagnostics-updated-hook))) + ((equal kind "unchanged") t) + (t (lsp--error "Unknown pull diagnostic result kind '%s'" kind)))) + (defun lsp--on-diagnostics (workspace params) "Callback for textDocument/publishDiagnostics. interface PublishDiagnosticsParams { @@ -3744,6 +3776,8 @@ disappearing, unset all the variables related to it." (publishDiagnostics . ((relatedInformation . t) (tagSupport . ((valueSet . [1 2]))) (versionSupport . t))) + (diagnostic . ((dynamicRegistration . :json-false) + (relatedDocumentSupport . :json-false))) (linkedEditingRange . ((dynamicRegistration . t))))) (window . ((workDoneProgress . t) (showDocument . ((support . t)))))) @@ -4809,7 +4843,8 @@ Added to `after-change-functions'." (with-lsp-workspace workspace (lsp-notify "textDocument/didChange" (list :contentChanges (vector (lsp--full-change-event)) - :textDocument (lsp--versioned-text-document-identifier)))))) + :textDocument (lsp--versioned-text-document-identifier))) + (lsp-diagnostics--request-pull-diagnostics workspace)))) (2 (with-lsp-workspace workspace (lsp-notify @@ -4819,7 +4854,8 @@ Added to `after-change-functions'." (if content-change-event-fn (funcall content-change-event-fn start end length) (lsp--text-document-content-change-event - start end length))))))))) + start end length))))) + (lsp-diagnostics--request-pull-diagnostics workspace))))) (lsp-workspaces)) (when lsp--delay-timer (cancel-timer lsp--delay-timer)) (setq lsp--delay-timer (run-with-idle-timer @@ -4828,14 +4864,7 @@ Added to `after-change-functions'." #'lsp--flush-delayed-changes)) ;; force cleanup overlays after each change (lsp--remove-overlays 'lsp-highlight) - (lsp--after-change (current-buffer)) - (setq lsp--signature-last-index nil - lsp--signature-last nil) - ;; cleanup diagnostics - (when lsp-diagnostic-clean-after-change - (lsp-foreach-workspace - (-let [diagnostics (lsp--workspace-diagnostics lsp--cur-workspace)] - (remhash (lsp--fix-path-casing (buffer-file-name)) diagnostics)))))))) + (lsp--after-change (current-buffer)))))) @@ -4892,6 +4921,16 @@ Added to `after-change-functions'." (run-hooks 'lsp-on-change-hook))) (defun lsp--after-change (buffer) + "Called after most textDocument/didChange events." + (setq lsp--signature-last-index nil + lsp--signature-last nil) + + ;; cleanup diagnostics + (when lsp-diagnostic-clean-after-change + (dolist (workspace (lsp-workspaces)) + (-let [diagnostics (lsp--workspace-diagnostics workspace)] + (remhash (lsp--fix-path-casing (buffer-file-name)) diagnostics)))) + (when (fboundp 'lsp--semantic-tokens-refresh-if-enabled) (lsp--semantic-tokens-refresh-if-enabled buffer)) (when lsp--on-change-timer diff --git a/lsp-protocol.el b/lsp-protocol.el index 034107a5b3..d5b98a00e5 100644 --- a/lsp-protocol.el +++ b/lsp-protocol.el @@ -603,10 +603,15 @@ See `-let' for a description of the destructuring mechanism." (DefinitionCapabilities nil (:dynamicRegistration :linkSupport)) (DeleteFileOptions nil (:ignoreIfNotExists :recursive)) (Diagnostic (:range :message) (:code :relatedInformation :severity :source :tags)) + (DiagnosticClientCapabilities nil (:dynamicRegistration :relatedDocumentSupport)) + (DiagnosticOptions (:interFileDependencies :workspaceDiagnostics) (:identifier)) (DiagnosticRelatedInformation (:location :message) nil) + (DiagnosticServerCancellationData (:retriggerRequest) nil) (DiagnosticsTagSupport (:valueSet) nil) (DidChangeConfigurationCapabilities nil (:dynamicRegistration)) (DidChangeWatchedFilesCapabilities nil (:dynamicRegistration)) + (DocumentDiagnosticParams (:textDocument) (:identifier :previousResultId)) + (DocumentDiagnosticReport (:kind) (:resultId :items :relatedDocuments)) (DocumentFilter nil (:language :pattern :scheme)) (DocumentHighlightCapabilities nil (:dynamicRegistration)) (DocumentLinkCapabilities nil (:dynamicRegistration :tooltipSupport)) From d89a01bd31a0820522dd65d314ff223c2295bd0c Mon Sep 17 00:00:00 2001 From: Ruin0x11 Date: Wed, 27 Dec 2023 23:01:44 -0600 Subject: [PATCH 2/3] Update CHANGELOG.org --- CHANGELOG.org | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.org b/CHANGELOG.org index 14d4485d31..6cb6b05fa4 100644 --- a/CHANGELOG.org +++ b/CHANGELOG.org @@ -7,6 +7,7 @@ * Add support for go to definition for external files (.dll) in CSharp projects for OmniSharp server. * Added a new optional ~:action-filter~ argument when defining LSP clients that allows code action requests to be modified before they are sent to the server. This is used by the Haskell language server client to work around an ~lsp-mode~ parsing quirk that incorrectly sends ~null~ values instead of ~false~ in code action requests. * Add support for C# via the [[https://github.com/dotnet/roslyn/tree/main/src/Features/LanguageServer][Roslyn language server]]. + * Add basic support for [[https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_pullDiagnostics][pull diagnostics]] requests. ** 9.0.0 * Add language server config for QML (Qt Modeling Language) using qmlls. From 6fc45a57f1c0a8d58ea0fc0dd87d46c94506517d Mon Sep 17 00:00:00 2001 From: Ruin0x11 Date: Wed, 27 Dec 2023 23:15:07 -0600 Subject: [PATCH 3/3] Request pull diagnostics when file is opened --- lsp-mode.el | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lsp-mode.el b/lsp-mode.el index fcee996256..790f14352a 100644 --- a/lsp-mode.el +++ b/lsp-mode.el @@ -4299,6 +4299,8 @@ yet." (lsp-managed-mode 1) + (lsp-diagnostics--request-pull-diagnostics lsp--cur-workspace) + (run-hooks 'lsp-after-open-hook) (when-let ((client (-some-> lsp--cur-workspace (lsp--workspace-client)))) (-some-> (lsp--client-after-open-fn client)