]> git.eshelyaron.com Git - emacs.git/commitdiff
Support functions as Flymake fixes in addition to lists of edits
authorEshel Yaron <me@eshelyaron.com>
Sun, 9 Jun 2024 10:37:27 +0000 (12:37 +0200)
committerEshel Yaron <me@eshelyaron.com>
Sun, 9 Jun 2024 10:37:27 +0000 (12:37 +0200)
lisp/progmodes/eglot.el
lisp/progmodes/flymake.el

index 9f4739dc7d826d2c95a42227302c39b635e90e54..e80193a85ad20843dba750953928897f32b78989 100644 (file)
@@ -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
index 0c5be469c5b7d1f83296e673c87d2116573362d9..2ca29dd930ca313adbe1a6797c53cfacadc0197f 100644 (file)
@@ -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")))