Package: emacs;
Reported by: Reuben Thomas <rrt <at> sc3d.org>
Date: Tue, 31 Jul 2012 12:02:02 UTC
Severity: wishlist
Tags: wontfix
Done: Lars Ingebrigtsen <larsi <at> gnus.org>
Bug is archived. No further changes may be made.
Message #54 received at control <at> debbugs.gnu.org (full text, mbox):
From: Stefan Kangas <stefan <at> marxist.se> To: Juri Linkov <juri <at> jurta.org> Cc: 12098 <at> debbugs.gnu.org, Reuben Thomas <rrt <at> sc3d.org> Subject: Re: bug#12098: How to trap errors in man? Date: Wed, 19 Aug 2020 12:49:39 +0000
severity 12098 wishlist tags 12098 + patch moreinfo thanks Juri Linkov <juri <at> jurta.org> writes: >> 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. This patch adds the possibility to run man asynchronously. I'm not sure it's worth the added complexity. Any other opinions? > === 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. Best regards, Stefan Kangas
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.