Subject: Re: bug#17831: 24.4.50; bad default value for `Man-width'

From: Juri Linkov <[email-masked]>
Date: Fri, 27 Jun 2014 02:49:55 +0300

>> This simple patch displays the buffer immediately,
>> but then slowly fills it with unformatted output
>> that doesn't look nice.
>
> Indeed, that's why I haven't made this change in Emacs years ago (when
> I made it in my local copy after getting too annoyed at the window-popup
> disruption).  The solution is obvious, tho: "Just" move the reformatting
> to the process-filter.

Using the same approach like processing escape sequences in grep/compilation
produces a nice result for M-x man: it displays the first formatted page
immediately and continues formatting the rest of the man page in background.
There are still small details to iron out but this is basically achieved
with the following patch.

There is one problem that I noticed on large man pages: formatting
small chunks by process-filter is little slower than formatting the
whole output like it currently does.  Could it be possible that
a slowdown is caused by `narrow-to-region'?  Then it's possible
to add two new arguments `min' and `max' to `Man-fontify-manpage'
to limit the processed region manually instead of using narrowing.

=== modified file 'lisp/man.el'
--- lisp/man.el	2014-05-09 07:02:00 +0000
+++ lisp/man.el	2014-06-27 00:49:22 +0000
@@ -1056,20 +1056,22 @@ (defun Man-getpage-in-background (topic)
       (require 'env)
       (message "Invoking %s %s in the background" manual-program man-args)
       (setq buffer (generate-new-buffer bufname))
+      (Man-notify-when-ready buffer)
       (with-current-buffer buffer
 	(setq buffer-undo-list t)
 	(setq Man-original-frame (selected-frame))
 	(setq Man-arguments man-args))
       (Man-start-calling
        (if (fboundp 'start-process)
-	    (set-process-sentinel
-	     (start-process manual-program buffer
-			    (if (memq system-type '(cygwin windows-nt))
-				shell-file-name
-			      "sh")
-			    shell-command-switch
-			    (format (Man-build-man-command) man-args))
-	     'Man-bgproc-sentinel)
+	   (let ((proc (start-process
+			manual-program buffer
+			(if (memq system-type '(cygwin windows-nt))
+			    shell-file-name
+			  "sh")
+			shell-command-switch
+			(format (Man-build-man-command) man-args))))
+	     (set-process-sentinel proc 'Man-bgproc-sentinel)
+	     (set-process-filter proc 'Man-bgproc-filter))
 	  (let ((exit-status
 		 (call-process shell-file-name nil (list buffer nil) nil
 			       shell-command-switch
@@ -1312,6 +1317,33 @@ (defun Man-cleanup-manpage (&optional in
   (Man-softhyphen-to-minus)
   (message "%s man page cleaned up" Man-arguments))
 
+(defun Man-bgproc-filter (process string)
+  "Manpage background process filter.
+When manpage command is run asynchronously, PROCESS is the process
+object for the manpage command; when manpage command is run
+synchronously, PROCESS is the name of the buffer where the manpage
+command is run.  Second argument STRING is the entire string of output."
+  (save-excursion
+    (let ((Man-buffer (if (stringp process) (get-buffer process)
+			(process-buffer process))))
+      (if (null (buffer-name Man-buffer)) ;; deleted buffer
+	  (or (stringp process)
+	      (set-process-buffer process nil))
+
+	(with-current-buffer Man-buffer
+	  (let ((inhibit-read-only t)
+	        (beg (marker-position (process-mark process))))
+	    (goto-char beg)
+	    (insert string)
+	    (save-restriction
+	      (narrow-to-region
+	       (save-excursion (goto-char beg) (line-beginning-position))
+	       (point))
+	      (if Man-fontify-manpage-flag
+		  (Man-fontify-manpage)
+		(Man-cleanup-manpage)))
+	    (set-marker (process-mark process) (point-max))))))))
+
 (defun Man-bgproc-sentinel (process msg)
   "Manpage background process sentinel.
 When manpage command is run asynchronously, PROCESS is the process
@@ -1365,9 +1398,6 @@ (defun Man-bgproc-sentinel (process msg)
 		 ))
         (if delete-buff
             (kill-buffer Man-buffer)
-          (if Man-fontify-manpage-flag
-              (Man-fontify-manpage)
-            (Man-cleanup-manpage))
 
           (run-hooks 'Man-cooked-hook)
 	  (Man-mode)
@@ -1378,11 +1408,6 @@ (defun Man-bgproc-sentinel (process msg)
 		(user-error "Can't find the %s manpage"
                             (Man-page-from-arguments args)))
 	    (set-buffer-modified-p nil))))
-	;; Restore case-fold-search before calling
-	;; Man-notify-when-ready because it may switch buffers.
-
-	(if (not delete-buff)
-	    (Man-notify-when-ready Man-buffer))
 
 	(if err-mess
 	    (error "%s" err-mess))