Cache file model contents in a buffer

* jupyter-rest-api.el (jupyter-api-content-buffer): New function.
(jupyter-api-insert-model-content): Use it.

* jupyter-tramp.el (jupyter-tramp-file-local-copy): Use it.
This commit is contained in:
Nathaniel Nicandro 2019-06-23 20:56:14 -05:00 committed by Nathaniel Nicandro
parent d018434b4a
commit 933e5c65a6
3 changed files with 48 additions and 27 deletions

View file

@ -1012,6 +1012,32 @@ otherwise nil."
"Return non-nil if MODEL corresponds to Jupyter notebook JSON."
(equal (plist-get model :type) "notebook"))
;; TODO: Replace the :content key with the buffer? It is redundant to have both
;; a string and a buffer holding the contents.
(defun jupyter-api-content-buffer (model)
"Return a buffer holding MODEL's content.
If MODEL's content is binary, the returned buffer will hold the
decoded content.
The returned buffer will be a single-byte buffer, i.e. will not
contain any multibyte characters.
Note, the returned buffer will be killed when MODEL is garbage
collected."
(cl-assert (member (plist-get model :format) '("text" "base64")))
(unless (bufferp (plist-get model :_buffer))
(let ((buffer (generate-new-buffer " *jupyter-api-model-content*")))
(with-current-buffer buffer
;; NOTE: Order of insertion matters here
(insert (or (plist-get model :content) ""))
(set-buffer-multibyte nil)
(plist-put model :_buffer (current-buffer))
(plist-put model :_finalizer (make-finalizer
(lambda () (kill-buffer buffer))))
(when (jupyter-api-binary-content-p model)
(base64-decode-region (point-min) (point-max))))))
(plist-get model :_buffer))
(defun jupyter-api-insert-model-content (model &optional replace beg end)
"Insert the content of MODEL into the current buffer.
If REPLACE is non-nil, replace the contents of the current buffer
@ -1019,21 +1045,13 @@ using `replace-buffer-contents'. BEG and END are byte offsets
into the content of MODEL, only insert the portion of MODEL's
contents bounded by BEG and END. BEG and END default to
`point-min' and `point-max' respectively."
(cl-assert (not (equal (plist-get model :type) "directory")))
(let ((source (generate-new-buffer " *temp*")))
(unwind-protect
(progn
(let ((source (jupyter-api-content-buffer model)))
(with-current-buffer source
(set-buffer-multibyte nil)
(insert (or (plist-get model :content) ""))
(when (jupyter-api-binary-content-p model)
;; TODO: Cache the result of decoding?
(base64-decode-region (point-min) (point-max)))
(widen)
(when (or beg end)
(narrow-to-region (or beg (point-min)) (or end (point-max)))))
(if replace (replace-buffer-contents source)
(insert-buffer-substring source)))
(and (buffer-live-p source) (kill-buffer source)))))
(insert-buffer-substring source))))
(provide 'jupyter-rest-api)

View file

@ -748,17 +748,18 @@ the server. For any other file, call ORIG, which is the function
;; Ensure we grab a fresh model since the cached version may be out of
;; sync with the server.
(jupyter-tramp-flush-file-properties v localname)
(let* ((model (jupyter-tramp-get-file-model filename))
(content (plist-get model :content)))
(let ((model (jupyter-tramp-get-file-model filename)))
(when (jupyter-api-notebook-p model)
(error "Notebooks not supported yet"))
(let ((coding-system-for-write
(if (jupyter-api-binary-content-p model)
'no-conversion
'utf-8-auto)))
(tramp-run-real-handler
'make-temp-file
(list "jupyter-tramp." nil (file-name-extension filename t)
(cond
((jupyter-api-binary-content-p model)
(base64-decode-string content))
((jupyter-api-notebook-p model)
(error "Notebooks not supported yet"))
(t content)))))))
(with-current-buffer (jupyter-api-content-buffer model)
(buffer-string))))))))
;;; File/directory attributes

View file

@ -77,7 +77,7 @@
(let* ((tfile (make-temp-file "file-local-copy"))
(jpyfile (expand-file-name (file-name-nondirectory tfile) "/jpy::/")))
(unwind-protect
(let ((contents (jupyter-new-uuid)))
(let ((contents (concat "αβ" (jupyter-new-uuid) "λ")))
(with-temp-file tfile
(insert contents))
(let ((lfile (file-local-copy jpyfile)))
@ -293,6 +293,8 @@
(ert-info ("Basic write")
(write-region "foo" nil jpyfile)
(should (equal (file-contents) "foo"))
(write-region "foλo" nil jpyfile)
(should (equal (file-contents) "foλo"))
(with-temp-buffer
(insert "foo")
(write-region nil nil jpyfile)