branch: elpa/cider
commit e1a1350d4fdca123d856f5bc294e338f6521dec8
Author: Bozhidar Batsov <[email protected]>
Commit: Bozhidar Batsov <[email protected]>

    Add keyword-arg forms of the nREPL request senders
    
    The eval and sync request senders carried long tails of positional
    optional arguments, forcing callers to pad with nil just to reach a
    later one (e.g. ". . . nil nil nil 'tooling").
    
    Introduce cl-defun keyword-argument primaries, nrepl-send-eval-request
    and nrepl-sync-request, and keep the old positional nrepl-request:eval
    and nrepl-send-sync-request as thin shims that delegate to them.  No
    obsolete markers, so existing positional callers (including third-party
    packages) keep working without warnings.  Same-file callers are routed
    through the new forms.
---
 lisp/nrepl-client.el       | 75 ++++++++++++++++++++++++++++++++++++----------
 test/nrepl-client-tests.el | 43 ++++++++++++++++++++++++++
 2 files changed, 102 insertions(+), 16 deletions(-)

diff --git a/lisp/nrepl-client.el b/lisp/nrepl-client.el
index 0405d777c7..f7933bf217 100644
--- a/lisp/nrepl-client.el
+++ b/lisp/nrepl-client.el
@@ -866,8 +866,8 @@ the standard session."
 (defvar nrepl-ongoing-sync-request nil
   "Dynamically bound to t while a sync request is ongoing.")
 
-(defun nrepl-send-sync-request (request connection &optional abort-on-input
-                                        tooling callback)
+(cl-defun nrepl-sync-request (request connection &key abort-on-input
+                                      tooling callback)
   "Send REQUEST to the nREPL server synchronously using CONNECTION.
 Hold till final \"done\" message has arrived and join all response messages
 of the same \"op\" that came along.
@@ -879,7 +879,10 @@ If CALLBACK is non-nil, it will additionally be called on 
all received
 messages.  This shouldn't be used this for any control logic - use the
 asynchronous `nrepl-send-request' directly for that.  CALLBACK here should
 be used to react to some intermediate events in an otherwise synchronous
-command and e.g. notify the user about them."
+command and e.g. notify the user about them.
+
+This is the keyword-argument form; `nrepl-send-sync-request' is the legacy
+positional shim retained for backward compatibility."
   (let* ((time0 (current-time))
          (response (cons 'dict nil))
          (nrepl-ongoing-sync-request t)
@@ -921,6 +924,28 @@ command and e.g. notify the user about them."
             (nrepl--mark-id-completed id)))
         response))))
 
+(defun nrepl-send-sync-request (request connection &optional abort-on-input
+                                        tooling callback)
+  "Send REQUEST to the nREPL server synchronously using CONNECTION.
+Hold till final \"done\" message has arrived and join all response messages
+of the same \"op\" that came along.
+If ABORT-ON-INPUT is non-nil, the function will return nil at the first
+sign of user input, so as not to hang the interface.
+If TOOLING, use the tooling session rather than the standard session.
+
+If CALLBACK is non-nil, it will additionally be called on all received
+messages.  This shouldn't be used this for any control logic - use the
+asynchronous `nrepl-send-request' directly for that.  CALLBACK here should
+be used to react to some intermediate events in an otherwise synchronous
+command and e.g. notify the user about them.
+
+This positional form is kept for backward compatibility; new code should
+prefer the keyword-argument `nrepl-sync-request'."
+  (nrepl-sync-request request connection
+                      :abort-on-input abort-on-input
+                      :tooling tooling
+                      :callback callback))
+
 (defun nrepl-request:stdin (input callback connection)
   "Send a :stdin request with INPUT using CONNECTION.
 Register CALLBACK as the response handler."
@@ -959,19 +984,38 @@ If LINE and COLUMN are non-nil and current buffer is a 
file buffer, \"line\",
             "line" ,line
             "column" ,column)))))
 
-(defun nrepl-request:eval (input callback connection &optional ns line column 
additional-params tooling)
+(cl-defun nrepl-send-eval-request (input callback connection
+                                         &key ns line column additional-params 
tooling)
   "Send the request INPUT and register the CALLBACK as the response handler.
 The request is dispatched via CONNECTION.  If NS is non-nil,
 include it in the request.  LINE and COLUMN, if non-nil, define the position
 of INPUT in its buffer.  A CONNECTION uniquely determines two connections
 available: the standard interaction one and the tooling session.  If the
 tooling is desired, set TOOLING to true.
-ADDITIONAL-PARAMS is a plist to be appended to the request message."
+ADDITIONAL-PARAMS is a plist to be appended to the request message.
+
+This is the keyword-argument form; `nrepl-request:eval' is the legacy
+positional shim retained for backward compatibility."
   (nrepl-send-request (append (nrepl--eval-request input ns line column) 
additional-params)
                       callback
                       connection
                       tooling))
 
+(defun nrepl-request:eval (input callback connection &optional ns line column 
additional-params tooling)
+  "Send the request INPUT and register the CALLBACK as the response handler.
+The request is dispatched via CONNECTION.  If NS is non-nil,
+include it in the request.  LINE and COLUMN, if non-nil, define the position
+of INPUT in its buffer.  A CONNECTION uniquely determines two connections
+available: the standard interaction one and the tooling session.  If the
+tooling is desired, set TOOLING to true.
+ADDITIONAL-PARAMS is a plist to be appended to the request message.
+
+This positional form is kept for backward compatibility; new code should
+prefer the keyword-argument `nrepl-send-eval-request'."
+  (nrepl-send-eval-request input callback connection
+                           :ns ns :line line :column column
+                           :additional-params additional-params :tooling 
tooling))
+
 (defvar nrepl-client-name "nrepl.el"
   "Name of the nREPL client, sent in clone requests.")
 
@@ -983,17 +1027,17 @@ ADDITIONAL-PARAMS is a plist to be appended to the 
request message."
 The request is dispatched via CONNECTION.
 Optional argument TOOLING Tooling is set to t if wanting the tooling session
 from CONNECTION."
-  (nrepl-send-sync-request `("op" "clone"
-                             "client-name" ,nrepl-client-name
-                             ,@(when nrepl-client-version
-                                 `("client-version" ,nrepl-client-version)))
-                           connection
-                           nil tooling))
+  (nrepl-sync-request `("op" "clone"
+                        "client-name" ,nrepl-client-name
+                        ,@(when nrepl-client-version
+                            `("client-version" ,nrepl-client-version)))
+                      connection
+                      :tooling tooling))
 
 (defun nrepl-sync-request:close (connection)
   "Sent a :close request to close CONNECTION's SESSION."
-  (nrepl-send-sync-request '("op" "close") connection)
-  (nrepl-send-sync-request '("op" "close") connection nil t)) ;; close tooling 
session
+  (nrepl-sync-request '("op" "close") connection)
+  (nrepl-sync-request '("op" "close") connection :tooling t)) ;; close tooling 
session
 
 (defun nrepl-sync-request:describe (connection)
   "Perform :describe request for CONNECTION and SESSION."
@@ -1014,11 +1058,10 @@ The request is dispatched via CONNECTION.
 If NS is non-nil, include it in the request
 If TOOLING is non-nil the evaluation is done using the tooling nREPL
 session."
-  (nrepl-send-sync-request
+  (nrepl-sync-request
    (nrepl--eval-request input ns)
    connection
-   nil
-   tooling))
+   :tooling tooling))
 
 (defun nrepl-sessions (connection)
   "Get a list of active sessions on the nREPL server using CONNECTION."
diff --git a/test/nrepl-client-tests.el b/test/nrepl-client-tests.el
index 5202a85643..1f9b0d0b1e 100644
--- a/test/nrepl-client-tests.el
+++ b/test/nrepl-client-tests.el
@@ -267,6 +267,49 @@
       (expect received-body :to-equal "hello")
       (expect received-type :to-equal '("text/plain" ())))))
 
+(describe "nrepl-send-eval-request"
+  (it "passes code, callback, connection and tooling through to 
nrepl-send-request"
+    (let (captured)
+      (spy-on 'nrepl-send-request :and-call-fake
+              (lambda (request callback connection &optional tooling)
+                (setq captured (list request callback connection tooling))))
+      (let ((cb (lambda (_))))
+        (nrepl-send-eval-request "(+ 1 1)" cb :fake-conn
+                                 :ns "user" :tooling 'tooling)
+        (cl-destructuring-bind (request callback connection tooling) captured
+          (expect callback :to-be cb)
+          (expect connection :to-be :fake-conn)
+          (expect tooling :to-be 'tooling)
+          (expect (nrepl-dict-get (cons 'dict request) "code") :to-equal "(+ 1 
1)")
+          (expect (nrepl-dict-get (cons 'dict request) "ns") :to-equal 
"user")))))
+
+  (it "produces the same request as the positional nrepl-request:eval shim"
+    (let (calls)
+      (spy-on 'nrepl-send-request :and-call-fake
+              (lambda (&rest args) (push args calls)))
+      (let ((cb (lambda (_))))
+        (nrepl-send-eval-request "(+ 1 1)" cb :fake-conn
+                                 :ns "user" :line 1 :column 2
+                                 :additional-params '("foo" "bar") :tooling 
'tooling)
+        (nrepl-request:eval "(+ 1 1)" cb :fake-conn
+                            "user" 1 2 '("foo" "bar") 'tooling))
+      (expect (length calls) :to-equal 2)
+      (expect (nth 0 calls) :to-equal (nth 1 calls)))))
+
+(describe "nrepl-send-sync-request"
+  (it "delegates to nrepl-sync-request with positional args mapped to keywords"
+    (let (captured)
+      (spy-on 'nrepl-sync-request :and-call-fake
+              (lambda (request connection &rest kwargs)
+                (setq captured (list request connection kwargs))))
+      (nrepl-send-sync-request '("op" "x") :fake-conn 'abort 'tooling #'ignore)
+      (cl-destructuring-bind (request connection kwargs) captured
+        (expect request :to-equal '("op" "x"))
+        (expect connection :to-be :fake-conn)
+        (expect (plist-get kwargs :abort-on-input) :to-be 'abort)
+        (expect (plist-get kwargs :tooling) :to-be 'tooling)
+        (expect (plist-get kwargs :callback) :to-be #'ignore)))))
+
 (describe "nrepl--dispatch-response"
   :var (nrepl-pending-requests nrepl-completed-requests)
   (before-each

Reply via email to