From 9285480715d0381b707dcd8c4753dbb7e23d61ff Mon Sep 17 00:00:00 2001 From: "Yuri D. Lensky" Date: Mon, 29 Mar 2021 18:42:58 -0700 Subject: [PATCH] Update jupyter--encode for new Emacs JSON API. The old Emacs JSON API (for versions <= 27.2 at time of commit) was structured in a way that replacing the symbol-function of json-encode worked to get custom encoding for certain object types used by emacs-jupyter. In the later API, the function json--print plays the recursive role of json-encode. The code here works in either version, and is simplified so that future updates to the API are easier to accomodate. --- jupyter-messages.el | 60 +++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/jupyter-messages.el b/jupyter-messages.el index 4754337..454e846 100644 --- a/jupyter-messages.el +++ b/jupyter-messages.el @@ -152,38 +152,34 @@ If PART is a list whose first element is the symbol, is non-nil. If it is nil, then set the list's second element to the result of calling `jupyter--encode' on the third element and return the result." - (if (eq (car-safe part) 'message-part) - (cl-destructuring-bind (_ encoded-rep decoded-rep) part - (or encoded-rep (setf (nth 1 part) (jupyter--encode decoded-rep)))) - (cl-letf (((symbol-function 'json-encode) - (lambda (object) - (cond ((memq object (list t json-null json-false)) - (json-encode-keyword object)) - ((stringp object) (json-encode-string object)) - ((keywordp object) - ;; Handle `jupyter-message-type' - (let ((msg-type (plist-get jupyter-message-types object))) - (json-encode-string - (or msg-type (substring (symbol-name object) 1))))) - ((symbolp object) (json-encode-string (symbol-name object))) - ((numberp object) (json-encode-number object)) - ((arrayp object) (json-encode-array object)) - ((hash-table-p object) (json-encode-hash-table object)) - ((listp object) - (cond - ((eq (car object) 'message-part) - (jupyter--encode object)) - ;; Turn time objects into ISO 8601 time strings - ((and (= (length object) 4) - (cl-every #'integerp object)) - (jupyter-encode-time object)) - (t (json-encode-list object)))) - (t (signal 'json-error (list object))))))) - (encode-coding-string - (cond - ((stringp part) part) - (t (json-encode part))) - 'utf-8 t)))) + (let ((json-recursive-encoder-sym (if (fboundp 'json--print) 'json--print 'json-encode))) + (unwind-protect + (progn + (add-function :around (symbol-function json-recursive-encoder-sym) #'jupyter--json-encode-preproc) + (encode-coding-string + (cond + ((stringp part) part) + (t (json-encode part))) + 'utf-8 t)) + (remove-function (symbol-function json-recursive-encoder-sym) #'jupyter--json-encode-preproc)))) + +(defun jupyter--json-encode-preproc (old-json-recursive-encoder object) + (let (msg-type) + (cl-flet ((json-encode + (object) + (jupyter--json-encode-preproc old-json-recursive-encoder object))) + (cond + ((eq (car-safe object) 'message-part) + (cl-destructuring-bind (_ encoded-rep decoded-rep) object + (or encoded-rep (setf (nth 1 object) (json-encode decoded-rep))))) + ((and (keywordp object) + (setf msg-type (plist-get jupyter-message-types object))) + (json-encode msg-type)) + ((and (listp object) + (= (length object) 4) + (cl-every #'integerp object)) + (jupyter-encode-time object)) + (t (funcall old-json-recursive-encoder object)))))) (defun jupyter--decode (part) "Decode a message PART.