[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
bug#12098: How to trap errors in man?
From: |
Stefan Kangas |
Subject: |
bug#12098: How to trap errors in man? |
Date: |
Wed, 19 Aug 2020 12:49:39 +0000 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) |
severity 12098 wishlist
tags 12098 + patch moreinfo
thanks
Juri Linkov <juri@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
- bug#12098: How to trap errors in man?,
Stefan Kangas <=
- bug#12098: How to trap errors in man?, Reuben Thomas, 2020/08/19
- bug#12098: How to trap errors in man?, Lars Ingebrigtsen, 2020/08/19
- bug#12098: How to trap errors in man?, Reuben Thomas, 2020/08/19
- bug#12098: How to trap errors in man?, Stefan Kangas, 2020/08/19
- bug#12098: How to trap errors in man?, Reuben Thomas, 2020/08/19
- bug#12098: How to trap errors in man?, Stefan Kangas, 2020/08/19
- bug#12098: How to trap errors in man?, Reuben Thomas, 2020/08/19
- bug#12098: How to trap errors in man?, Stefan Kangas, 2020/08/19
- bug#12098: How to trap errors in man?, Reuben Thomas, 2020/08/19