Improve eww support for externally viewed PDFs

The *eww pdf* buffer is only needed when viewing PDFs within Emacs,
e.g., with doc-view-mode.  External PDF viewers are called with a
temporary file, so the buffer is not needed in that case.  What's
more, mailcap-view-mime erased the buffer and left it in
fundamental-mode until now, so the user was left staring at a
useless, empty buffer.  To make things even worse, external viewers
were invoked synchronously until now, so the user could not browse
the PDF file and use Emacs simultaneously.

* lisp/net/mailcap.el (mailcap--async-shell): New function.
(mailcap-view-mime): Use it to invoke external viewers
asynchronously.  Mention erasure of current buffer in that case in
docstring.  Add a period between the temporary file name and its
extension.

* lisp/net/eww.el (eww-display-pdf): Simplify using
insert-buffer-substring.  Fix coding-system-for-write for a stream
of raw bytes.  Pop to *eww pdf* buffer only if it is used for
displaying a document; otherwise kill it.  (bug#44338)
This commit is contained in:
Basil L. Contovounesios 2020-11-03 22:54:34 +00:00
parent 38a109e58c
commit bfd3124202
2 changed files with 33 additions and 18 deletions

View file

@ -811,14 +811,19 @@ Currently this means either text/html or application/xhtml+xml."
(declare-function mailcap-view-mime "mailcap" (type))
(defun eww-display-pdf ()
(let ((data (buffer-substring (point) (point-max))))
(pop-to-buffer-same-window (get-buffer-create "*eww pdf*"))
(let ((coding-system-for-write 'raw-text)
(inhibit-read-only t))
(erase-buffer)
(insert data)
(mailcap-view-mime "application/pdf")))
(goto-char (point-min)))
(let ((buf (current-buffer))
(pos (point)))
(with-current-buffer (get-buffer-create "*eww pdf*")
(let ((coding-system-for-write 'raw-text-unix)
(inhibit-read-only t))
(erase-buffer)
(insert-buffer-substring buf pos)
(mailcap-view-mime "application/pdf"))
(if (zerop (buffer-size))
;; Buffer contents passed to shell command via temporary file.
(kill-buffer)
(goto-char (point-min))
(pop-to-buffer-same-window (current-buffer))))))
(defun eww-setup-buffer ()
(when (or (plist-get eww-data :url)

View file

@ -1131,20 +1131,30 @@ For instance, \"foo.png\" will result in \"image/png\"."
res)))
(nreverse res)))))
(defun mailcap--async-shell (command file)
"Asynchronously call MIME viewer shell COMMAND.
Replace %s in COMMAND with FILE, as per `mailcap-mime-data'.
Delete FILE once COMMAND exits."
(let ((buf (get-buffer-create " *mailcap shell*")))
(async-shell-command (format command file) buf)
(add-function :after (process-sentinel (get-buffer-process buf))
(lambda (proc _msg)
(when (memq (process-status proc) '(exit signal))
(delete-file file))))))
(defun mailcap-view-mime (type)
"View the data in the current buffer that has MIME type TYPE.
`mailcap--computed-mime-data' determines the method to use."
The variable `mailcap--computed-mime-data' determines the method
to use. If the method is a shell command string, erase the
current buffer after passing its contents to the shell command."
(let ((method (mailcap-mime-info type)))
(if (stringp method)
(let ((file (make-temp-file "emacs-mailcap" nil
(cadr (split-string type "/")))))
(unwind-protect
(let ((coding-system-for-write 'binary))
(write-region (point-min) (point-max) file nil 'silent)
(delete-region (point-min) (point-max))
(shell-command (format method file)))
(when (file-exists-p file)
(delete-file file))))
(let* ((ext (concat "." (cadr (split-string type "/"))))
(file (make-temp-file "emacs-mailcap" nil ext))
(coding-system-for-write 'binary))
(write-region nil nil file nil 'silent)
(delete-region (point-min) (point-max))
(mailcap--async-shell method file))
(funcall method))))
(provide 'mailcap)