From 5a206611e27a11a9b3e23159ee6e15030ad30368 Mon Sep 17 00:00:00 2001 From: Troy Brown Date: Sat, 20 Apr 2024 01:40:06 -0400 Subject: [PATCH 1/2] Fix Flymake diagnostic column off-by-one error. --- lsp-diagnostics.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lsp-diagnostics.el b/lsp-diagnostics.el index b10f0ca220..1ce1b8070b 100644 --- a/lsp-diagnostics.el +++ b/lsp-diagnostics.el @@ -298,7 +298,7 @@ See https://github.com/emacs-lsp/lsp-mode." (when (= start end) (if-let ((region (flymake-diag-region (current-buffer) (1+ start-line) - character))) + (1+ character)))) (setq start (car region) end (cdr region)) (lsp-save-restriction-and-excursion From a686a77e0579a04eff5db406966619afd6ff880e Mon Sep 17 00:00:00 2001 From: Troy Brown Date: Sat, 20 Apr 2024 02:08:47 -0400 Subject: [PATCH 2/2] Add a defcustom to control default diagnostic severity. Previously, there was a Flycheck specific defcustom, which was used to select a default error level for Flycheck. However, there was nothing for Flymake. Additionally, there were numerous other places in lsp-mode which query the severity attribute of the diagnostic, such as for statistics, modeline, headerline, etc. All of these were being handled inconsistently, either not at all (causing an error when the attribute was not sent by the server), ignoring it when it was missing (causing statistics to be inaccurate) or assuming a default of error, which might have been different than the Flycheck specific configuration, therefore causing an inconsistency in the modeline statistics vs what Flycheck would report. This change creates a common defcustom which is then used anywhere the diagnostic severity is needed, but was not provided by the server. This should create consistent statistics between the modeline and the back-end checkers. Additionally, the mapping between this defcustom and the checker specific values happens in the diagnostic package. Since this defcustom is used outside of the lsp-diagnostic package, it resides in the lsp-mode package and renamed more generally. Additionally, the Flycheck specific defcustom has been obsoleted. --- lsp-diagnostics.el | 51 ++++++++++++++++++++++------------------------ lsp-headerline.el | 6 +++++- lsp-mode.el | 25 +++++++++++++++++++++-- lsp-modeline.el | 6 ++++-- 4 files changed, 56 insertions(+), 32 deletions(-) diff --git a/lsp-diagnostics.el b/lsp-diagnostics.el index 1ce1b8070b..a5eb860987 100644 --- a/lsp-diagnostics.el +++ b/lsp-diagnostics.el @@ -50,13 +50,9 @@ (define-obsolete-variable-alias 'lsp-flycheck-default-level 'lsp-diagnostics-flycheck-default-level "lsp-mode 7.0.1") -(defcustom lsp-diagnostics-flycheck-default-level 'error - "Error level to use when the server does not report back a diagnostic level." - :type '(choice - (const error) - (const warning) - (const info)) - :group 'lsp-diagnostics) +;;;###autoload +(define-obsolete-variable-alias 'lsp-diagnostics-flycheck-default-level + 'lsp-diagnostics-default-severity "lsp-mode 9.0.1") (defcustom lsp-diagnostics-attributes `((unnecessary :foreground "gray") @@ -131,18 +127,19 @@ g. `error', `warning') and list of LSP TAGS." (defun lsp-diagnostics--flycheck-calculate-level (severity tags) "Calculate flycheck level by SEVERITY and TAGS." - (let ((level (pcase severity - (1 'error) - (2 'warning) - (3 'info) - (4 'info) - (_ lsp-flycheck-default-level))) - ;; materialize only first tag. - (tags (seq-map (lambda (tag) - (cond - ((= tag lsp/diagnostic-tag-unnecessary) 'unnecessary) - ((= tag lsp/diagnostic-tag-deprecated) 'deprecated))) - tags))) + (let* ((severity (or severity + (lsp-diagnostics-severity->numeric + lsp-diagnostics-default-severity))) + (level (cond ((= severity lsp/diagnostic-severity-error) 'error) + ((= severity lsp/diagnostic-severity-warning) 'warning) + ((= severity lsp/diagnostic-severity-information) 'info) + ((= severity lsp/diagnostic-severity-hint) 'info))) + ;; materialize only first tag. + (tags (seq-map (lambda (tag) + (cond + ((= tag lsp/diagnostic-tag-unnecessary) 'unnecessary) + ((= tag lsp/diagnostic-tag-deprecated) 'deprecated))) + tags))) (if tags (lsp-diagnostics--flycheck-level level tags) level))) @@ -305,14 +302,14 @@ See https://github.com/emacs-lsp/lsp-mode." (goto-char (point-min)) (setq start (line-beginning-position (1+ start-line)) end (line-end-position (1+ end-line)))))) - (flymake-make-diagnostic (current-buffer) - start - end - (cl-case severity? - (1 :error) - (2 :warning) - (t :note)) - message)))) + (let* ((severity (or severity? + (lsp-diagnostics-severity->numeric + lsp-diagnostics-default-severity))) + (type (cond ((= severity lsp/diagnostic-severity-error) :error) + ((= severity lsp/diagnostic-severity-warning) :warning) + ((= severity lsp/diagnostic-severity-information) :note) + ((= severity lsp/diagnostic-severity-hint) :note)))) + (flymake-make-diagnostic (current-buffer) start end type message))))) ;; This :region keyword forces flymake to delete old diagnostics in ;; case the buffer hasn't changed since the last call to the report ;; function. See https://github.com/joaotavora/eglot/issues/159 diff --git a/lsp-headerline.el b/lsp-headerline.el index cbdc765417..b69d978cc4 100644 --- a/lsp-headerline.el +++ b/lsp-headerline.el @@ -306,7 +306,11 @@ PATH is the current folder to be checked." (let ((range-severity 10)) (mapc (-lambda ((&Diagnostic :range (&Range :start) :severity?)) (when (lsp-point-in-range? start range) - (setq range-severity (min range-severity severity?)))) + (setq range-severity + (min range-severity + (or severity? + (lsp-diagnostics-severity->numeric + lsp-diagnostics-default-severity)))))) (lsp--get-buffer-diagnostics)) range-severity)) diff --git a/lsp-mode.el b/lsp-mode.el index e599af2def..b35dee4654 100644 --- a/lsp-mode.el +++ b/lsp-mode.el @@ -634,6 +634,15 @@ diagnostics have changed." :type 'hook :group 'lsp-mode) +(defcustom lsp-diagnostics-default-severity 'error + "Error level to use when the server does not report one." + :type '(choice (const :tag "Error" error) + (const :tag "Warning" warning) + (const :tag "Information" info) + (const :tag "Hint" hint)) + :group 'lsp-mode + :package-version '(lsp-mode . "9.0.1")) + (define-obsolete-variable-alias 'lsp-workspace-folders-changed-hook 'lsp-workspace-folders-changed-functions "lsp-mode 6.3") @@ -2277,6 +2286,14 @@ Common usecase are: result))) (ht))) +(defun lsp-diagnostics-severity->numeric (severity) + "Determine numeric severity from symbolic SEVERITY." + (pcase severity + ('error lsp/diagnostic-severity-error) + ('warning lsp/diagnostic-severity-warning) + ('info lsp/diagnostic-severity-information) + ('hint lsp/diagnostic-severity-hint))) + (defun lsp-diagnostics-stats-for (path) "Get diagnostics statistics for PATH. The result format is vector [_ errors warnings infos hints] or nil." @@ -2296,11 +2313,15 @@ The result format is vector [_ errors warnings infos hints] or nil." (let ((path (lsp--fix-path-casing (lsp--uri-to-path uri))) (new-stats (make-vector 5 0))) (mapc (-lambda ((&Diagnostic :severity?)) - (cl-incf (aref new-stats (or severity? 1)))) + (cl-incf (aref new-stats (or severity? + (lsp-diagnostics-severity->numeric + lsp-diagnostics-default-severity))))) diagnostics) (when-let ((old-diags (gethash path (lsp--workspace-diagnostics workspace)))) (mapc (-lambda ((&Diagnostic :severity?)) - (cl-decf (aref new-stats (or severity? 1)))) + (cl-decf (aref new-stats (or severity? + (lsp-diagnostics-severity->numeric + lsp-diagnostics-default-severity))))) old-diags)) (lsp-diagnostics--update-path path new-stats) (while (not (string= path (setf path (file-name-directory diff --git a/lsp-modeline.el b/lsp-modeline.el index 9449f5c8b0..0199b91ad4 100644 --- a/lsp-modeline.el +++ b/lsp-modeline.el @@ -229,8 +229,10 @@ The `:global' workspace is global one.") (mapc (lambda (buf-diags) (mapc (lambda (diag) (-let [(&Diagnostic? :severity?) diag] - (when severity? - (cl-incf (aref stats severity?))))) + (cl-incf (aref stats + (or severity? + (lsp-diagnostics-severity->numeric + lsp-diagnostics-default-severity)))))) buf-diags)) diagnostics) (while (< i lsp/diagnostic-severity-max)