From 45f1e427fc8b5722b1179eff6375d3da24299ddc Mon Sep 17 00:00:00 2001 From: Tassilo Horn Date: Sat, 15 Jan 2022 11:23:46 +0100 Subject: [PATCH] mailcap: Docfix & handle function-viewer case in mailcap-view-file * lisp/net/mailcap.el (mailcap-mime-data): Fix docstring: if viewer is a symbol/function, it should have zero args and expect the file's contents to be in the current buffer. (mailcap-view-file): Implement the case where the chosen viewer is a function and not a shell command. --- lisp/net/mailcap.el | 72 ++++++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 30 deletions(-) diff --git a/lisp/net/mailcap.el b/lisp/net/mailcap.el index daa2d5a3fb3..b65f7c25b83 100644 --- a/lisp/net/mailcap.el +++ b/lisp/net/mailcap.el @@ -319,8 +319,9 @@ attribute name (viewer, test, etc). This looks like: Where VIEWERINFO specifies how the content-type is viewed. Can be a string, in which case it is run through a shell, with appropriate -parameters, or a symbol, in which case the symbol is `funcall'ed if -and only if it exists as a function, with the buffer as an argument. +parameters, or a symbol, in which case the symbol must name a function +of zero arguments which is called in a buffer holding the MIME part's +content. TESTINFO is a test for the viewer's applicability, or nil. If nil, it means the viewer is always valid. If it is a Lisp function, it is @@ -1175,34 +1176,45 @@ See \"~/.mailcap\", `mailcap-mime-data' and related files and variables." (mailcap-parse-mailcaps) (let ((command (mailcap-mime-info (mailcap-extension-to-mime (file-name-extension file))))) - (unless command - (error "No viewer for %s" (file-name-extension file))) - ;; Remove quotes around the file name - we'll use shell-quote-argument. - (while (string-match "['\"]%s['\"]" command) - (setq command (replace-match "%s" t t command))) - (setq command (replace-regexp-in-string - "%s" - (shell-quote-argument (convert-standard-filename file)) - command - nil t)) - ;; Handlers such as "gio open" and kde-open5 start viewer in background - ;; and exit immediately. Avoid `start-process' since it assumes - ;; :connection-type `pty' and kills children processes with SIGHUP - ;; when temporary terminal session is finished (Bug#44824). - ;; An alternative is `process-connection-type' let-bound to nil for - ;; `start-process-shell-command' call (with no chance to report failure). - (make-process - :name "mailcap-view-file" - :connection-type 'pipe - :buffer nil ; "*Messages*" may be suitable for debugging - :sentinel (lambda (proc event) - (when (and (memq (process-status proc) '(exit signal)) - (/= (process-exit-status proc) 0)) - (message - "Command %s: %s." - (mapconcat #'identity (process-command proc) " ") - (substring event 0 -1)))) - :command (list shell-file-name shell-command-switch command)))) + (if (functionp command) + ;; command is a viewer function (a mode) expecting the file + ;; contents to be in the current buffer. + (let ((buf (generate-new-buffer (file-name-nondirectory file)))) + (set-buffer buf) + (insert-file-contents file) + (setq buffer-file-name file) + (funcall command) + (set-buffer-modified-p nil) + (pop-to-buffer buf)) + ;; command is a program to run with file as an argument. + (unless command + (error "No viewer for %s" (file-name-extension file))) + ;; Remove quotes around the file name - we'll use shell-quote-argument. + (while (string-match "['\"]%s['\"]" command) + (setq command (replace-match "%s" t t command))) + (setq command (replace-regexp-in-string + "%s" + (shell-quote-argument (convert-standard-filename file)) + command + nil t)) + ;; Handlers such as "gio open" and kde-open5 start viewer in background + ;; and exit immediately. Avoid `start-process' since it assumes + ;; :connection-type `pty' and kills children processes with SIGHUP + ;; when temporary terminal session is finished (Bug#44824). + ;; An alternative is `process-connection-type' let-bound to nil for + ;; `start-process-shell-command' call (with no chance to report failure). + (make-process + :name "mailcap-view-file" + :connection-type 'pipe + :buffer nil ; "*Messages*" may be suitable for debugging + :sentinel (lambda (proc event) + (when (and (memq (process-status proc) '(exit signal)) + (/= (process-exit-status proc) 0)) + (message + "Command %s: %s." + (mapconcat #'identity (process-command proc) " ") + (substring event 0 -1)))) + :command (list shell-file-name shell-command-switch command))))) (provide 'mailcap) -- 2.39.2