From 560bbed4e21aaefd3825e8290c4e70460144f73a Mon Sep 17 00:00:00 2001 From: Eshel Yaron Date: Sun, 9 Jun 2024 12:37:27 +0200 Subject: [PATCH] Support functions as Flymake fixes in addition to lists of edits --- lisp/progmodes/eglot.el | 72 +++++++++++++++++++++------------------ lisp/progmodes/flymake.el | 36 ++++++++++---------- 2 files changed, 57 insertions(+), 51 deletions(-) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index 9f4739dc7d8..e80193a85ad 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -2389,42 +2389,48 @@ Value is (TRUENAME . (:uri STR)), where STR is what is sent to the server on textDocument/didOpen and similar calls. TRUENAME is the expensive cached value of `file-truename'.") -(defun eglot--flymake-fix (data) - "Return fix suggestions for Flymake diagnostic with DATA." +(defun eglot--flymake-fix (server data) + "Return fix suggestions from SERVER for Flymake diagnostic with DATA." (eglot--dbind ((Diagnostic) range) (alist-get 'eglot-lsp-diag data) (pcase-let ((`(,beg . ,end) (eglot--diag-range-region range))) (let ((actions (eglot-code-actions beg end "quickfix"))) (seq-keep - (eglot--lambda ((CodeAction) title edit) - (eglot--dbind - ((WorkspaceEdit) changes documentChanges) - edit - (let ((prepared - (mapcar - (eglot--lambda ((TextDocumentEdit) textDocument edits) - (eglot--dbind ((VersionedTextDocumentIdentifier) - uri version) - textDocument - (list (eglot-uri-to-path uri) edits version))) - documentChanges))) - (unless (and changes documentChanges) - (cl-loop for (uri edits) on changes by #'cddr - do (push (list (eglot-uri-to-path uri) edits) - prepared))) - (when prepared - (list title - (mapcar - (pcase-lambda (`(,file ,edits . ,_)) - (let ((buf (find-file-noselect file))) - (cons buf - (seq-map (eglot--lambda ((TextEdit) - range newText) - (pcase (with-current-buffer buf - (eglot-range-region range)) - (`(,beg . ,end) - (list beg end newText)))) - edits)))) - prepared)))))) + (eglot--lambda ((CodeAction) title edit command) + (cond + (edit + (eglot--dbind + ((WorkspaceEdit) changes documentChanges) + edit + (let ((prepared + (mapcar + (eglot--lambda ((TextDocumentEdit) textDocument edits) + (eglot--dbind ((VersionedTextDocumentIdentifier) + uri version) + textDocument + (list (eglot-uri-to-path uri) edits version))) + documentChanges))) + (unless (and changes documentChanges) + (cl-loop for (uri edits) on changes by #'cddr + do (push (list (eglot-uri-to-path uri) edits) + prepared))) + (when prepared + (list title + (mapcar + (pcase-lambda (`(,file ,edits . ,_)) + (let ((buf (find-file-noselect file))) + (cons buf + (seq-map (eglot--lambda ((TextEdit) + range newText) + (pcase (with-current-buffer buf + (eglot-range-region range)) + (`(,beg . ,end) + (list beg end newText)))) + edits)))) + prepared)))))) + (command + (list title + (lambda () + (eglot--request server :workspace/executeCommand command)))))) actions))))) (defun eglot--diag-range-region (range) @@ -2489,7 +2495,7 @@ expensive cached value of `file-truename'.") when (alist-get tag eglot--tag-faces) collect it))) `((face . ,faces))) - #'eglot--flymake-fix))) + (apply-partially #'eglot--flymake-fix server)))) into diags finally (cond ((and ;; only add to current report if Flymake diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el index 0c5be469c5b..2ca29dd930c 100644 --- a/lisp/progmodes/flymake.el +++ b/lisp/progmodes/flymake.el @@ -402,11 +402,9 @@ the diagnostic's type symbol. FIX-FUNCTION, if non-nil, is a function that takes DATA and returns a list of fix suggestions for this diagnostic. Each fix suggestion is a list (TITLE EDITS), where TITLE is a string describing the fix and EDITS -is a list of (FILE-OR-BUFFER . CHANGES) cons cells, where FILE-OR-BUFFER -is the file name or buffer to edit, and CHANGES is a list of changes to -perform in FILE-OR-BUFFER. Each element of CHANGES is in turn a -list (BEG END STR), where BEG and END are buffer positions to delete and -STR is the string to insert at BEG afterwards." +is a list of edits in the format that `refactor-apply-edits' expects. +Alternatively, EDITS can also be a function of no arguments that +performs the fix." (when (stringp locus) (setq locus (expand-file-name locus))) (flymake--diag-make :locus locus :beg beg :end end @@ -870,11 +868,13 @@ Return to original margin width if ORIG-WIDTH is non-nil." (i 1)) (dolist (fix fixes) (define-key menu (vector (intern (format "flymake-fix-%d" i))) - `(menu-item ,(format "Fix: %s" (car fix)) - ,(lambda () - (interactive) - (refactor-apply-edits (cadr fix))) - ,@(cddr fix))) + `(menu-item + ,(format "Fix: %s" (car fix)) + ,(let ((edits (cadr fix))) + (if (functionp edits) + (lambda () (interactive) (funcall edits)) + (lambda () (interactive) (refactor-apply-edits edits)))) + ,@(cddr fix))) (cl-incf i))) menu) @@ -885,14 +885,14 @@ Return to original margin width if ORIG-WIDTH is non-nil." (if-let ((diags (flymake-diagnostics pos))) (if-let ((diag (seq-find #'flymake--diag-fix-function diags)) (fixes (funcall (flymake--diag-fix-function diag) - (flymake--diag-data diag)))) - (refactor-apply-edits - (car (if (cdr fixes) - (alist-get - (completing-read (format-prompt "Fix" (caar fixes)) - fixes nil t nil nil (caar fixes)) - fixes nil nil #'string=) - (cdar fixes)))) + (flymake--diag-data diag))) + (edits (car (if (cdr fixes) + (alist-get + (completing-read (format-prompt "Fix" (caar fixes)) + fixes nil t nil nil (caar fixes)) + fixes nil nil #'string=) + (cdar fixes))))) + (if (functionp edits) (funcall edits) (refactor-apply-edits edits)) (message "No fix available for this diagnostic")) (user-error "No diagnostic at this position"))) -- 2.39.2