[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/eglot 0e1a5f0 05/69: jrpc-connect is now passed a gener
From: |
João Távora |
Subject: |
[elpa] externals/eglot 0e1a5f0 05/69: jrpc-connect is now passed a generic dispatching function |
Date: |
Fri, 22 Jun 2018 11:54:54 -0400 (EDT) |
branch: externals/eglot
commit 0e1a5f07f0163d92fb66f711b6b3e291e866229e
Author: João Távora <address@hidden>
Commit: João Távora <address@hidden>
jrpc-connect is now passed a generic dispatching function
* eglot.el (eglot--dispatch): New helper.
(eglot--connect): Use it.
* jrpc.el (jrpc--dispatcher, jrpc--request-continuations)
(jrpc--server-request-ids): New process-local var.
(jrpc--pending-continuations, jrpc--method-prefix): Remove.
(jrpc-connect): Take DISPATCHER instead of PREFIX.
(jrpc--process-receive): Use proc's dispatcher.
(jrpc--process-send): Make private.
(jrpc-forget-pending-continuations, jrpc-async-request)
(jrpc-reply, jrpc-notify): Use new function names.
---
eglot.el | 11 +++++-
jrpc.el | 128 +++++++++++++++++++++++++++++++++------------------------------
2 files changed, 78 insertions(+), 61 deletions(-)
diff --git a/eglot.el b/eglot.el
index 879972d..13aeff6 100644
--- a/eglot.el
+++ b/eglot.el
@@ -277,9 +277,18 @@ INTERACTIVE is t if called interactively."
(defvar eglot-connect-hook nil "Hook run after connecting in
`eglot--connect'.")
+(defun eglot--dispatch (proc method id &rest params)
+ ;; a server notification or a server request
+ (let* ((handler-sym (intern (concat "eglot--server-" method))))
+ (if (functionp handler-sym)
+ (apply handler-sym proc (append params (if id `(:id ,id))))
+ (jrpc-reply
+ proc id
+ :error (jrpc-obj :code -32601 :message "Unimplemented")))))
+
(defun eglot--connect (project managed-major-mode name command
dont-inhibit)
- (let ((proc (jrpc-connect name command "eglot--server-"
#'eglot--on-shutdown)))
+ (let ((proc (jrpc-connect name command #'eglot--dispatch
#'eglot--on-shutdown)))
(setf (eglot--project proc) project)
(setf (eglot--major-mode proc)managed-major-mode)
(push proc (gethash project eglot--processes-by-project))
diff --git a/jrpc.el b/jrpc.el
index 973e901..ea0122b 100644
--- a/jrpc.el
+++ b/jrpc.el
@@ -25,14 +25,6 @@
;; Originally extracted from eglot.el (Emacs LSP client)
;;
;;
-;; code message meaning
-;; -32700 Parse error Invalid JSON was received by the server.
-;; An error occurred on the server while parsing the JSON text.
-;; -32600 Invalid Request The JSON sent is not a valid Request object.
-;; -32601 Method not found The method does not exist / is not
available.
-;; -32602 Invalid params Invalid method parameter(s).
-;; -32603 Internal error Internal JSON-RPC error.
-
;;; Code:
(require 'cl-lib)
@@ -98,8 +90,8 @@ INITVAL is the default value. DOC is the documentation."
(jrpc-define-process-var jrpc-name nil
"A name for the process")
-(jrpc-define-process-var jrpc--method-prefix nil
- "Emacs-lisp function prefix for server-invoked methods.")
+(jrpc-define-process-var jrpc--dispatcher nil
+ "Emacs-lisp function for server-invoked methods.")
(jrpc-define-process-var jrpc-status `(:unknown nil)
"Status as declared by the server.
@@ -108,8 +100,11 @@ A list (WHAT SERIOUS-P).")
(jrpc-define-process-var jrpc--expected-bytes nil
"How many bytes declared by server")
-(jrpc-define-process-var jrpc--pending-continuations (make-hash-table)
- "A hash table of request ID to continuation lambdas")
+(jrpc-define-process-var jrpc--request-continuations (make-hash-table)
+ "A hash table of request ID to continuation lambdas.")
+
+(jrpc-define-process-var jrpc--server-request-ids nil
+ "Server-initiated request id that client hasn't replied to.")
(jrpc-define-process-var jrpc--events-buffer nil
"A buffer pretty-printing the JSON-RPC RPC events")
@@ -128,7 +123,7 @@ A function passed the process object for the server.")
(defun jrpc-outstanding-request-ids (proc)
"IDs of outstanding JSON-RPC requests for PROC."
- (hash-table-keys (jrpc--pending-continuations proc)))
+ (hash-table-keys (jrpc--request-continuations proc)))
(defun jrpc--make-process (name contact)
"Make a process from CONTACT.
@@ -164,7 +159,7 @@ CONTACT is as `jrpc-contact'. Returns a process object."
;; the indenting of literal plists, i.e. is basically `list'
`(list ,@what))
-(cl-defun jrpc-connect (name contact prefix &optional on-shutdown)
+(cl-defun jrpc-connect (name contact dispatcher &optional on-shutdown)
"Connect to JSON-RPC server hereafter known as NAME through CONTACT.
NAME is a string naming the server.
@@ -173,21 +168,35 @@ CONTACT is either a list of strings (a shell command and
arguments), or a list of a single string of the form
<host>:<port>.
-PREFIX specifies how the server-invoked methods find their Elisp
-counterpart. If a server invokes method \"FooBar\" and PREFIX is
-\"fancy-mode-\", then the function `fancy-mode-FooBar' will be
-called with arguments (PROCESS [JSON]). JSON is either a plist of
-key-value pairs or, for JSON arrays, a non-list sequence.
-
ON-SHUTDOWN, when non-nil, is a function called on server exit
and passed the moribund process object.
-Returns a process object representing the server."
+DISPATCHER specifies how the server-invoked methods find their
+Elisp counterpart. It is a function which is passed (PROC METHOD
+ID PARAMS...) as arguments.
+
+PROC is the process object returned by this function.
+
+ID is server identifier for a server request, or nil for a server
+notification.
+
+METHOD is a symbol.
+
+PARAMS contains the method parameters. If the parameters are a
+JSON object, PARAMS... is a plist of the form (KEY1 VALUE1 KEY2
+VALUE2...). It they are an array, a string or a number, the
+first and only element of PARAMS is a vector, string or number,
+respectively. If the parameters are a single boolean, PARAMS is
+either the symbol `:json-false' or `t'. In the case of a server
+request, DISPATCHER is reponsible for replying to it with
+`jrpc-reply' (which see).
+
+`jrpc-connect' returns a process object representing the server."
(let* ((proc (jrpc--make-process name contact))
(buffer (process-buffer proc)))
(setf (jrpc-contact proc) contact
(jrpc-name proc) name
- (jrpc--method-prefix proc) prefix
+ (jrpc--dispatcher proc) dispatcher
(jrpc--on-shutdown proc) on-shutdown)
(with-current-buffer buffer
(let ((inhibit-read-only t))
@@ -206,13 +215,13 @@ Returns a process object representing the server."
(maphash (lambda (_id triplet)
(cl-destructuring-bind (_success _error timeout) triplet
(cancel-timer timeout)))
- (jrpc--pending-continuations proc))
+ (jrpc--request-continuations proc))
(unwind-protect
;; Call all outstanding error handlers
(maphash (lambda (_id triplet)
(cl-destructuring-bind (_success error _timeout) triplet
(funcall error :code -1 :message (format "Server died"))))
- (jrpc--pending-continuations proc))
+ (jrpc--request-continuations proc))
(jrpc-message "Server exited with status %s" (process-exit-status proc))
(funcall (or (jrpc--on-shutdown proc) #'identity) proc)
(delete-process proc))))
@@ -322,29 +331,27 @@ is a symbol saying if this is a client or server
originated."
(defun jrpc--process-receive (proc message)
"Process MESSAGE from PROC."
- (cl-destructuring-bind (&key method id error &allow-other-keys) message
+ (cl-destructuring-bind (&key method id error params &allow-other-keys)
message
(let* ((continuations (and id
(not method)
- (gethash id (jrpc--pending-continuations
proc)))))
+ (gethash id (jrpc--request-continuations
proc)))))
(jrpc-log-event proc message 'server)
(when error (setf (jrpc-status proc) `(,error t)))
(cond (method
- ;; a server notification or a server request
- (let* ((handler-sym (intern (concat (jrpc--method-prefix proc)
- method))))
- (if (functionp handler-sym)
- (apply handler-sym proc (append
- (plist-get message :params)
- (if id `(:id ,id))))
- (jrpc-warn "No implementation of method %s yet" method)
- (when id
- (jrpc-reply
- proc id
- :error (jrpc-obj :code -32601
- :message "Method unimplemented"))))))
+ (unwind-protect
+ (if (listp params)
+ (apply (jrpc--dispatcher proc) proc method id params)
+ (funcall (jrpc--dispatcher proc) proc method id params))
+ (unless (or (not id)
+ (member id (jrpc--server-request-ids proc)))
+ (jrpc-reply
+ proc id
+ :error (jrpc-obj :code -32603 :message "Internal error")))
+ (setf (jrpc--server-request-ids proc)
+ (delete id (jrpc--server-request-ids proc)))))
(continuations
(cancel-timer (cl-third continuations))
- (remhash id (jrpc--pending-continuations proc))
+ (remhash id (jrpc--request-continuations proc))
(if error
(apply (cl-second continuations) error)
(let ((res (plist-get message :result)))
@@ -356,7 +363,7 @@ is a symbol saying if this is a client or server
originated."
(jrpc--call-deferred proc)
(force-mode-line-update t))))
-(defun jrpc-process-send (proc message)
+(defun jrpc--process-send (proc message)
"Send MESSAGE to PROC (ID is optional)."
(let ((json (json-encode message)))
(process-send-string proc (format "Content-Length: %d\r\n\r\n%s"
@@ -370,10 +377,10 @@ is a symbol saying if this is a client or server
originated."
"Compute the next id for a client request."
(setq jrpc--next-request-id (1+ jrpc--next-request-id)))
-(defun jrpc-forget-pending-continuations (process)
- "Stop waiting for responses from the current LSP PROCESS."
+(defun jrpc-forget-pending-continuations (proc)
+ "Stop waiting for responses from the current LSP PROC."
(interactive (list (jrpc-current-process-or-lose)))
- (clrhash (jrpc--pending-continuations process)))
+ (clrhash (jrpc--request-continuations proc)))
(defun jrpc-clear-status (process)
"Clear most recent error message from PROCESS."
@@ -417,7 +424,7 @@ timeout keeps counting."
(run-with-timer
timeout nil
(lambda ()
- (remhash id (jrpc--pending-continuations proc))
+ (remhash id (jrpc--request-continuations proc))
(funcall (or timeout-fn
(lambda ()
(jrpc-error
@@ -454,11 +461,11 @@ timeout keeps counting."
proc (jrpc-obj :message "error ignored, status set"
:id id :error code)))
(funcall make-timeout))
- (jrpc--pending-continuations proc))
- (jrpc-process-send proc (jrpc-obj :jsonrpc "2.0"
- :id id
- :method method
- :params params))))
+ (jrpc--request-continuations proc))
+ (jrpc--process-send proc (jrpc-obj :jsonrpc "2.0"
+ :id id
+ :method method
+ :params params))))
(defun jrpc-request (proc method params &optional deferred)
"Like `jrpc-async-request' for PROC, METHOD and PARAMS, but synchronous.
@@ -489,16 +496,17 @@ DEFERRED is passed to `jrpc-async-request', which see."
(cl-defun jrpc-notify (process method params)
"Notify PROCESS of something, don't expect a reply.e"
- (jrpc-process-send process (jrpc-obj :jasonrpc "2.0"
- :method method
- :params params)))
-
-(cl-defun jrpc-reply (process id &key result error)
- "Reply to PROCESS's request ID with MESSAGE."
- (jrpc-process-send
- process `(:jasonrpc "2.0" :id ,id
- ,@(when result `(:result ,result))
- ,@(when error `(:error ,error)))))
+ (jrpc--process-send process (jrpc-obj :jasonrpc "2.0"
+ :method method
+ :params params)))
+
+(cl-defun jrpc-reply (proc id &key result error)
+ "Reply to PROCESS's request ID with RESULT or ERROR."
+ (push id (jrpc--server-request-ids proc))
+ (jrpc--process-send
+ proc`(:jasonrpc "2.0" :id ,id
+ ,@(when result `(:result ,result))
+ ,@(when error `(:error ,error)))))
(defun jrpc-mapply (fun seq)
"Apply FUN to every element of SEQ."
- [elpa] externals/eglot updated (0176264 -> f385d9c), João Távora, 2018/06/22
- [elpa] externals/eglot f4de5d7 01/69: Fix copyright header. Obviously not since 2003, João Távora, 2018/06/22
- [elpa] externals/eglot 5cda0ec 06/69: Fix a ridiculous bug when generating transient projects, João Távora, 2018/06/22
- [elpa] externals/eglot e5120aa 08/69: Add jrpc.el to Makefile, João Távora, 2018/06/22
- [elpa] externals/eglot 07359a2 15/69: Allow null timeouts and set default to 3 seconds, João Távora, 2018/06/22
- [elpa] externals/eglot 67d8335 17/69: jrpc.el should know nothing of mode-line updates, João Távora, 2018/06/22
- [elpa] externals/eglot 0e1a5f0 05/69: jrpc-connect is now passed a generic dispatching function,
João Távora <=
- [elpa] externals/eglot 078a1a6 13/69: Add full "Commentary" section to jrpc.el, João Távora, 2018/06/22
- [elpa] externals/eglot 2f1d76d 03/69: Proper server shutdown when jrpc.el is used, João Távora, 2018/06/22
- [elpa] externals/eglot a2aa1ed 19/69: Robustify timer handling for jrpc-async-request, João Távora, 2018/06/22
- [elpa] externals/eglot 7769c07 16/69: Send message, then establish continuations, João Távora, 2018/06/22
- [elpa] externals/eglot 7f2e894 11/69: Merge branch 'master' into jsonrpc-refactor (using good ol' git merge), João Távora, 2018/06/22
- [elpa] externals/eglot e5ba4f6 18/69: Automatically reply with error if dispatcher doesn't, João Távora, 2018/06/22
- [elpa] externals/eglot 33ae871 09/69: More flexible jrpc.el and improve eglot.el's doc, João Távora, 2018/06/22
- [elpa] externals/eglot 3265c1d 10/69: Simpler callback protocol for JSONRPC parameters and results, João Távora, 2018/06/22
- [elpa] externals/eglot e906d25 14/69: Overhaul JSON and JSRONRPC error handling, João Távora, 2018/06/22
- [elpa] externals/eglot 7cd94b9 12/69: Improve jrpc.el's doc (and change jrpc-request's protocol a tiny bit), João Távora, 2018/06/22