emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/eglot 147f3b0 16/49: Close #411: offer shortcut command


From: Stefan Monnier
Subject: [elpa] externals/eglot 147f3b0 16/49: Close #411: offer shortcut commands to commonly invoked code actions
Date: Wed, 17 Mar 2021 18:41:44 -0400 (EDT)

branch: externals/eglot
commit 147f3b0c10048d90315f9e43f3ddaf3718d3bc29
Author: Andrii Kolomoiets <andreyk.mad@gmail.com>
Commit: GitHub <noreply@github.com>

    Close #411: offer shortcut commands to commonly invoked code actions
    
    See also #598.
    
    Make eglot-code-actions accept a new action-kind argument.  If there
    is only one action of that kind, apply it.  This allows us to create
    actions shortcuts like eglot-code-action-organize-imports, etc.
    
    * eglot.el (eglot-code-actions): Accept new argument action-kind.
    (eglot--code-action): New function-defining helper macro.
    (eglot-code-action-organize-imports)
    (eglot-code-action-extract)
    (eglot-code-action-inline)
    (eglot-code-action-rewrite)
    (eglot-code-action-quickfix): New commands.
    
    * README.md: Mention new feature.
    
    * NEWS.md: Mention new feature.
    
    Co-authored-by: João Távora <joaotavora@gmail.com>
---
 NEWS.md   | 20 +++++++++++++++-
 README.md | 10 ++++----
 eglot.el  | 79 ++++++++++++++++++++++++++++++++++++++++++---------------------
 3 files changed, 77 insertions(+), 32 deletions(-)

diff --git a/NEWS.md b/NEWS.md
index cb72ba3..1b373bc 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,4 +1,17 @@
-# 1.7 (upcoming)
+# (upcoming)
+
+##### Code action shortcuts ([#411][github#411])
+
+`M-x eglot-code-actions` accepts an optional `action-kind` argument,
+specified interactively with `C-u`.  Other shortcuts call specific
+actions directly (`eglot-code-action-inline`,
+`eglot-code-action-extract`, `eglot-code-action-rewrite`,
+`eglot-code-action-organize-imports` and
+`eglot-code-action-quickfix`).  One can create own shortcuts for code
+actions with specific a kind by calling `eglot-code-actions` from
+elisp.
+
+# 1.7 (16/12/2020)
 
 ##### Support hierarchical symbols in Imenu ([#303][github#303])
 
@@ -232,3 +245,8 @@ and now said bunch of references-->
 [github#324]: https://github.com/joaotavora/eglot/issues/324
 [github#326]: https://github.com/joaotavora/eglot/issues/326
 [github#361]: https://github.com/joaotavora/eglot/issues/361
+[github#411]: https://github.com/joaotavora/eglot/issues/411
+[github#439]: https://github.com/joaotavora/eglot/issues/439
+[github#454]: https://github.com/joaotavora/eglot/issues/454
+[github#481]: https://github.com/joaotavora/eglot/issues/481
+[github#494]: https://github.com/joaotavora/eglot/issues/494
diff --git a/README.md b/README.md
index 7194241..d42eefc 100644
--- a/README.md
+++ b/README.md
@@ -217,10 +217,9 @@ Here's a summary of available commands:
 - `M-x eglot-format` asks the server to format buffer or the active
   region;
 
-- `M-x eglot-code-actions` asks the server for any code actions at
-  point. These may tipically be simple fixes, like deleting an unused
-  variable, or fixing an import. Left click on diagnostics to check if
-  there are any there;
+- `M-x eglot-code-actions` asks the server for any "code actions" at
+  point. Can also be invoked by `mouse-1`-clicking some diagnostics.
+  Also `M-x eglot-code-action-<TAB>` for shortcuts to specific actions.
 
 - `M-x eldoc` asks the Eldoc system for help at point (this command
   isn't specific to Eglot, by the way, it works in other contexts).
@@ -241,9 +240,10 @@ in `eglot-mode-map`, which is active as long as Eglot is 
managing a
 file in your project. The commands don't need to be Eglot-specific,
 either:
 
-```
+```lisp
 (define-key eglot-mode-map (kbd "C-c h") 'eglot-help-at-point)
 (define-key eglot-mode-map (kbd "<f6>") 'xref-find-definitions)
+(define-key eglot-mode-map (kbd "C-c o") 'eglot-code-action-organize-imports)
 ```
 
 <a name="customization"></a>
diff --git a/eglot.el b/eglot.el
index 8cfe991..276cd1a 100644
--- a/eglot.el
+++ b/eglot.el
@@ -2523,14 +2523,21 @@ is not active."
                                            :newName ,newname))
    current-prefix-arg))
 
-
-(defun eglot-code-actions (beg &optional end)
-  "Offer to execute code actions between BEG and END.
-Interactively, if a region is active, BEG and END are its bounds,
-else BEG is point and END is nil, which results in a request for
-code actions at point"
+(defun eglot--region-bounds () "Region bounds if active, else point and nil."
+  (if (use-region-p) `(,(region-beginning) ,(region-end)) `(,(point) nil)))
+
+(defun eglot-code-actions (beg &optional end action-kind)
+  "Offer to execute actions of ACTION-KIND between BEG and END.
+If ACTION-KIND is nil, consider all kinds of actions.
+Interactively, default BEG and END to region's bounds else BEG is
+point and END is nil, which results in a request for code actions
+at point.  With prefix argument, prompt for ACTION-KIND."
   (interactive
-   (if (region-active-p) `(,(region-beginning) ,(region-end)) `(,(point) nil)))
+   `(,@(eglot--region-bounds)
+     ,(and current-prefix-arg
+           (completing-read "[eglot] Action kind: "
+                            '("quickfix" "refactor.extract" "refactor.inline"
+                              "refactor.rewrite" "source.organizeImports")))))
   (unless (eglot--server-capable :codeActionProvider)
     (eglot--error "Server can't execute code actions!"))
   (let* ((server (eglot--current-server-or-lose))
@@ -2544,27 +2551,35 @@ code actions at point"
                  :context
                  `(:diagnostics
                    [,@(cl-loop for diag in (flymake-diagnostics beg end)
-                               when (cdr (assoc 'eglot-lsp-diag 
(eglot--diag-data diag)))
-                               collect it)]))))
+                               when (cdr (assoc 'eglot-lsp-diag
+                                                (eglot--diag-data diag)))
+                               collect it)]
+                   ,@(when action-kind `(:only ,action-kind))))))
          (menu-items
-          (or (mapcar (jsonrpc-lambda (&rest all &key title &allow-other-keys)
-                        (cons title all))
-                      actions)
-              (eglot--error "No code actions here")))
+          (or (cl-loop for action across actions
+                       ;; Do filtering ourselves, in case the `:only'
+                       ;; didn't go through.
+                       when (or (not action-kind)
+                                (equal action-kind (plist-get action :kind)))
+                       collect (cons (plist-get action :title) action))
+              (apply #'eglot--error
+                     (if action-kind `("No \"%s\" code actions here" 
,action-kind)
+                       `("No code actions here")))))
          (preferred-action (cl-find-if
-                            (jsonrpc-lambda (&key isPreferred 
&allow-other-keys)
-                              isPreferred)
-                            actions))
-         (menu `("Eglot code actions:" ("dummy" ,@menu-items)))
-         (action (if (listp last-nonmenu-event)
-                     (x-popup-menu last-nonmenu-event menu)
-                   (cdr (assoc (completing-read "[eglot] Pick an action: "
-                                                menu-items nil t
-                                                nil nil (or (plist-get
-                                                             preferred-action
-                                                             :title)
-                                                            (car menu-items)))
-                               menu-items)))))
+                            (lambda (menu-item)
+                              (plist-get (cdr menu-item) :isPreferred))
+                            menu-items))
+         (default-action (car (or preferred-action (car menu-items))))
+         (action (if (and action-kind (null (cadr menu-items)))
+                     (cdr (car menu-items))
+                   (if (listp last-nonmenu-event)
+                       (x-popup-menu last-nonmenu-event `("Eglot code actions:"
+                                                          ("dummy" 
,@menu-items)))
+                     (cdr (assoc (completing-read
+                                  (format "[eglot] Pick an action (default 
%s): "
+                                          default-action)
+                                  menu-items nil t nil nil default-action)
+                                 menu-items))))))
     (eglot--dcase action
       (((Command) command arguments)
        (eglot-execute-command server (intern command) arguments))
@@ -2574,6 +2589,18 @@ code actions at point"
          (eglot--dbind ((Command) command arguments) command
            (eglot-execute-command server (intern command) arguments)))))))
 
+(defmacro eglot--code-action (name kind)
+  "Define NAME to execute KIND code action."
+  `(defun ,name (beg &optional end)
+     ,(format "Execute '%s' code actions between BEG and END." kind)
+     (interactive (eglot--region-bounds))
+     (eglot-code-actions beg end ,kind)))
+
+(eglot--code-action eglot-code-action-organize-imports 
"source.organizeImports")
+(eglot--code-action eglot-code-action-extract "refactor.extract")
+(eglot--code-action eglot-code-action-inline "refactor.inline")
+(eglot--code-action eglot-code-action-rewrite "refactor.rewrite")
+(eglot--code-action eglot-code-action-quickfix "quickfix")
 
 
 ;;; Dynamic registration



reply via email to

[Prev in Thread] Current Thread [Next in Thread]