From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Juri Linkov Newsgroups: gmane.emacs.bugs Subject: bug#12098: How to trap errors in man? Date: Wed, 01 Aug 2012 11:23:30 +0300 Organization: JURTA Message-ID: <87txwnxbbx.fsf@mail.jurta.org> References: <87pq7b5uvr.fsf@mail.jurta.org> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: dough.gmane.org 1343810162 24611 80.91.229.3 (1 Aug 2012 08:36:02 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Wed, 1 Aug 2012 08:36:02 +0000 (UTC) Cc: 12098@debbugs.gnu.org To: Reuben Thomas Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Wed Aug 01 10:36:02 2012 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1SwUPO-0007Ij-1l for geb-bug-gnu-emacs@m.gmane.org; Wed, 01 Aug 2012 10:35:58 +0200 Original-Received: from localhost ([::1]:44366 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SwUPK-0001SK-EP for geb-bug-gnu-emacs@m.gmane.org; Wed, 01 Aug 2012 04:35:54 -0400 Original-Received: from eggs.gnu.org ([208.118.235.92]:41519) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SwUPC-0001Ls-AF for bug-gnu-emacs@gnu.org; Wed, 01 Aug 2012 04:35:52 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1SwUP5-00040v-Eo for bug-gnu-emacs@gnu.org; Wed, 01 Aug 2012 04:35:46 -0400 Original-Received: from debbugs.gnu.org ([140.186.70.43]:44421) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SwUP5-00040r-BL for bug-gnu-emacs@gnu.org; Wed, 01 Aug 2012 04:35:39 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.72) (envelope-from ) id 1SwUWE-0003oI-D9 for bug-gnu-emacs@gnu.org; Wed, 01 Aug 2012 04:43:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Juri Linkov Original-Sender: debbugs-submit-bounces@debbugs.gnu.org Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Wed, 01 Aug 2012 08:43:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 12098 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: Original-Received: via spool by 12098-submit@debbugs.gnu.org id=B12098.134381054414587 (code B ref 12098); Wed, 01 Aug 2012 08:43:02 +0000 Original-Received: (at 12098) by debbugs.gnu.org; 1 Aug 2012 08:42:24 +0000 Original-Received: from localhost ([127.0.0.1]:53963 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.72) (envelope-from ) id 1SwUVb-0003nC-AC for submit@debbugs.gnu.org; Wed, 01 Aug 2012 04:42:24 -0400 Original-Received: from ps18281.dreamhost.com ([69.163.218.105]:47605 helo=ps18281.dreamhostps.com) by debbugs.gnu.org with esmtp (Exim 4.72) (envelope-from ) id 1SwUVW-0003mw-1r for 12098@debbugs.gnu.org; Wed, 01 Aug 2012 04:42:21 -0400 Original-Received: from localhost (ps18281.dreamhostps.com [69.163.218.105]) by ps18281.dreamhostps.com (Postfix) with ESMTP id 2A6F2451CB7F; Wed, 1 Aug 2012 01:34:52 -0700 (PDT) In-Reply-To: (Reuben Thomas's message of "Wed, 1 Aug 2012 01:38:17 +0100") User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.1.50 (x86_64-pc-linux-gnu) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.13 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) X-Received-From: 140.186.70.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.bugs:62707 Archived-At: > There are plenty of things that freeze the session for much longer > than the fraction of a second it takes to format most man pages! Even > bash(1) only takes about a second. You are right, the largest man page `man bash' takes just 2 sec to format, so perhaps it makes no sense to run the man command asynchronously nowadays. The patch below introduces a new variable `Man-async' whose value could be set to nil to run `man' synchronously. > Are you sure about that bug number? I looked and it seems to be about > window layout. That's right, currently the async mode of man has its peculiarities: it arranges window layouts after formatting is done, so formatting can't fit into window layout. So perhaps we should have two asynchronous modes: 1. delay changes in window configuration until the process is finished and man page is formatted. 2. prepare window layout before formatting; I'm still not sure whether we need the former for backward compatibility, so `Man-async' could have a special value for it. > I can't see how to use this to communicate back to a particular caller > that man failed; help? I don't know if it's possible with lack of multi-threading to yield to the command loop while waiting for the process output. But with the following patch you can run `man' synchronously by using just `(let ((Man-async nil)) (man "bash"))' when its default value is not nil. === modified file 'lisp/man.el' --- lisp/man.el 2012-07-11 23:13:41 +0000 +++ lisp/man.el 2012-08-01 08:23:10 +0000 @@ -144,6 +144,20 @@ (defcustom Man-reverse-face 'highlight :type 'face :group 'man) +(defcustom Man-async nil + "Synchronicity of the manpage command. +If nil, run the manpage command synchronously. +If t, run the manpage command asynchronously +preparing output windows before the process is started. +If the value is `delayed', run the manpage command +asynchronously but delay changes in window configuration +until the process is finished and man page is formatted." + :type '(choice (const :tag "Synchronous" nil) + (const :tag "Asynchronous" t) + (const :tag "Delayed" delayed)) + :group 'man + :version "24.2") + ;; Use the value of the obsolete user option Man-notify, if set. (defcustom Man-notify-method (if (boundp 'Man-notify) Man-notify 'friendly) "Selects the behavior when manpage is ready. @@ -904,16 +920,37 @@ (defun Man-getpage-in-background (topic) Return the buffer in which the manpage will appear." (let* ((man-args topic) (bufname (concat "*Man " man-args "*")) - (buffer (get-buffer bufname))) + (buffer (get-buffer bufname)) + (procbufname (concat " " bufname)) + procbuffer) (if buffer (Man-notify-when-ready buffer) (require 'env) - (message "Invoking %s %s in the background" manual-program man-args) - (setq buffer (generate-new-buffer bufname)) - (with-current-buffer buffer - (setq buffer-undo-list t) - (setq Man-original-frame (selected-frame)) - (setq Man-arguments man-args)) + (cond + ((eq Man-async 'delayed) + (message "Invoking %s %s in the background" manual-program man-args) + (setq buffer (generate-new-buffer bufname)) + (with-current-buffer buffer + (setq buffer-undo-list t) + (setq Man-original-frame (selected-frame)) + (setq Man-arguments man-args))) + (t + (setq buffer (generate-new-buffer bufname)) + (setq procbuffer (generate-new-buffer procbufname)) + ;; Display empty output buffer. + (unless (memq Man-notify-method '(polite quiet meek)) + (Man-notify-when-ready buffer)) + (with-current-buffer buffer + (insert (format "Invoking %s %s in the background\n" + manual-program man-args)) + (setq buffer-undo-list t) + (setq Man-original-frame (selected-frame)) + (setq Man-arguments man-args)) + (with-current-buffer procbuffer + (setq buffer-undo-list t) + (setq Man-original-frame (selected-frame)) + (setq Man-arguments man-args)))) + (let ((process-environment (copy-sequence process-environment)) ;; The following is so Awk script gets \n intact ;; But don't prevent decoding of the outside. @@ -952,16 +989,26 @@ (defun Man-getpage-in-background (topic) (cond ((and (integerp Man-width) (> Man-width 0)) Man-width) - (Man-width (frame-width)) - ((window-width)))))) + (Man-width + (if (eq Man-async 'delayed) + (frame-width) + (with-selected-window (get-buffer-window + buffer t) + (frame-width)))) + (t + (if (eq Man-async 'delayed) + (window-width) + (with-selected-window (get-buffer-window + buffer t) + (window-width)))))))) (setenv "GROFF_NO_SGR" "1") ;; Since man-db 2.4.3-1, man writes plain text with no escape ;; sequences when stdout is not a tty. In 2.5.0, the following ;; env-var was added to allow control of this (see Debian Bug#340673). (setenv "MAN_KEEP_FORMATTING" "1") - (if (fboundp 'start-process) + (if (and Man-async (fboundp 'start-process)) (set-process-sentinel - (start-process manual-program buffer + (start-process manual-program (if (eq Man-async 'delayed) buffer procbuffer) (if (memq system-type '(cygwin windows-nt)) shell-file-name "sh") @@ -969,7 +1016,7 @@ (defun Man-getpage-in-background (topic) (format (Man-build-man-command) man-args)) 'Man-bgproc-sentinel) (let ((exit-status - (call-process shell-file-name nil (list buffer nil) nil + (call-process shell-file-name nil (list procbuffer nil) nil shell-command-switch (format (Man-build-man-command) man-args))) (msg "")) @@ -980,7 +1027,7 @@ (defun Man-getpage-in-background (topic) (format "exited abnormally with code %d" exit-status))) (setq msg exit-status)) - (Man-bgproc-sentinel bufname msg))))) + (Man-bgproc-sentinel procbufname msg))))) buffer)) (defun Man-notify-when-ready (man-buffer) @@ -1216,16 +1263,18 @@ (defun Man-bgproc-sentinel (process msg) synchronously, PROCESS is the name of the buffer where the manpage command is run. Second argument MSG is the exit message of the manpage command." - (let ((Man-buffer (if (stringp process) (get-buffer process) - (process-buffer process))) - (delete-buff nil) - (err-mess nil)) + (let* ((Man-procbuffer (if (stringp process) (get-buffer process) + (process-buffer process))) + (Man-buffer (get-buffer (replace-regexp-in-string + "\\` " "" (buffer-name Man-procbuffer)))) + (delete-buff nil) + (err-mess nil)) (if (null (buffer-name Man-buffer)) ;; deleted buffer (or (stringp process) (set-process-buffer process nil)) - (with-current-buffer Man-buffer + (with-current-buffer Man-procbuffer (let ((case-fold-search nil)) (goto-char (point-min)) (cond ((or (looking-at "No \\(manual \\)*entry for") @@ -1261,11 +1310,17 @@ (defun Man-bgproc-sentinel (process msg) (Man-fontify-manpage) (Man-cleanup-manpage)) + (unless (eq Man-async 'delayed) + (copy-to-buffer Man-buffer (point-min) (point-max)))))) + + (unless delete-buff + (with-current-buffer (if (eq Man-async 'delayed) Man-procbuffer Man-buffer) (run-hooks 'Man-cooked-hook) (Man-mode) @@ -1279,11 +1342,13 @@ (defun Man-bgproc-sentinel (process msg) ;; Man-notify-when-ready because it may switch buffers. (if (not delete-buff) - (Man-notify-when-ready Man-buffer)) + (when (or (eq Man-async 'delayed) + (memq Man-notify-method '(polite quiet meek))) + (Man-notify-when-ready Man-buffer))) (if err-mess (error "%s" err-mess)) - )))) + ))) (defun Man-page-from-arguments (args) ;; Skip arguments and only print the page name.