Subject: bug#5054: Man truncated (was: buffer-menu truncated fields)

From: Juri Linkov <[email-masked]>
Date: Mon, 11 Jan 2010 02:48:39 +0200

> I've been using a local hack which causes the *man...* buffers to be
> displayed early rather than late.  The main reason was to avoid
> interrupting me with a new frame at some random time in the future.
>
> So I'd welcome such a change.  My local hack isn't installable as is:
> the output shown temporarily in the buffer is rather ugly (because the
> buffer first gets an unprocessed output and then cleans it up and adds
> faces.  Usually the intermediate ugly states are not shown, but after my
> change, they are).

Using a separate buffer for the process output (a hidden buffer with
a leading space in its name) where `man' collects and formats the output
and later copies to the displayed main buffer is implemented in the
following patch.

One remaining problem: when `man' can't find a manpage, it signals
the error "Can't find the manpage".  But what to do with the displayed
empty window that waits for the formatted output?  Maybe to undo
the window configuration to its original state?  And what to do
with the created frame?  To leave it displaying an empty buffer?

=== modified file 'lisp/man.el'
--- lisp/man.el	2010-01-09 23:53:06 +0000
+++ lisp/man.el	2010-01-11 00:47:07 +0000
@@ -880,13 +880,25 @@
   "Use TOPIC to build and fire off the manpage and cleaning command."
   (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))
+      (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))
@@ -927,8 +939,14 @@
 			     (cond
 			      ((and (integerp Man-width) (> Man-width 0))
 			       Man-width)
-			      (Man-width (frame-width))
-			      ((window-width))))))
+			      (Man-width
+			       (with-selected-window (get-buffer-window
+						      buffer t)
+				 (frame-width)))
+			      (t
+			       (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
@@ -936,7 +954,7 @@
 	(setenv "MAN_KEEP_FORMATTING" "1")
 	(if (fboundp 'start-process)
 	    (set-process-sentinel
-	     (start-process manual-program buffer
+	     (start-process manual-program procbuffer
 			    (if (memq system-type '(cygwin windows-nt))
 				shell-file-name
 			      "sh")
@@ -944,7 +962,7 @@
 			    (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 ""))
@@ -955,7 +973,7 @@
 			   (format "exited abnormally with code %d"
 				   exit-status)))
 		(setq msg exit-status))
-	    (Man-bgproc-sentinel bufname msg)))))))
+	    (Man-bgproc-sentinel procbufname msg)))))))
 
 (defun Man-notify-when-ready (man-buffer)
   "Notify the user when MAN-BUFFER is ready.
@@ -1179,16 +1197,18 @@
 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")
@@ -1224,11 +1244,18 @@
 		       (insert (format "\nprocess %s" msg))))
 		 ))
         (if delete-buff
+	    ;; FIXME: also undo window configuration?
             (kill-buffer Man-buffer)
           (if Man-fontify-manpage-flag
               (Man-fontify-manpage)
             (Man-cleanup-manpage))
 
+	  (copy-to-buffer Man-buffer (point-min) (point-max)))))
+
+      (kill-buffer Man-procbuffer)
+
+      (unless delete-buff
+	(with-current-buffer Man-buffer
           (run-hooks 'Man-cooked-hook)
 	  (Man-mode)
 
@@ -1243,11 +1270,12 @@
 	;; Man-notify-when-ready because it may switch buffers.
 
 	(if (not delete-buff)
-	    (Man-notify-when-ready Man-buffer))
+	    (when (memq Man-notify-method '(polite quiet meek))
+	      (Man-notify-when-ready Man-buffer)))
 
 	(if err-mess
 	    (error "%s" err-mess))
-	))))
+	)))
 
 
 ;; ======================================================================

-- 
Juri Linkov
http://www.jurta.org/emacs/