If you try to open rclone or gcc man pages with Emacs, you'd be surprised how unpleasant that experience can be. Those pages are over 30K lines and Emacs will became unresponsive easily. For how long will depend on your CPU.
To speed up things, setting Man-fontify-manpage-flag
to nil can
alleviate this problem - it will disable highlighting of a man page
and buffer can be somehow usable. Surprisingly, running woman
, an
alternative man pager written in elisp, will render the rclone man page
faster, but it will leave a lot of garbage around.
The fastest option for me was running a shell command man <page> | col -b
and reading that output directly as plain text in the Emacs buffer.
However, running it with (shell-command-to-string)
would still
temporarily block Emacs until man
finish rendering the page. But we
can do it better.
Let's use (async-shell-command)
instead and leave a man
rendering
the content in the background, but at the same time, capture the
output in our buffer.
Here is an elisp function for that:
(defun faster-man (page)
"Get a Un*x manual page and put it in a buffer.
Faster alternative to (man) and (woman)."
(interactive
(list
;; autocompletion machinery stolen from (man)
(let* ((default-entry (Man-default-man-entry))
(completion-ignore-case t)
; no cache across calls for completion table
Man-completion-cache
(input (completing-read
(format "Manual entry%s"
(if (string= "" default-entry)
": "
(format " (default %s): " default-entry)))
'Man-completion-table
nil nil nil 'Man-topic-history default-entry)))
(if (string= "" input)
(error "No args given")
input))))
(let* ((buffer (pop-to-buffer (format "*Faster Man - %s*" page))))
(with-current-buffer buffer
(erase-buffer)
(let ((proc
(progn
;; Actual shell command. Redirect troff warnings & errors to /dev/null
;; so it doesn't pollute the output. Also, quote man page so it can display
;; things like "printf(3)"
(async-shell-command (format "man \"%s\" 2> /dev/null | col -b" page) buffer)
(get-buffer-process buffer))))
(when (process-live-p proc)
;; wait for process to finish, then apply fundamental-mode on it
;; and jump to the beginning of buffer
(set-process-sentinel proc (lambda (process signal)
(when (memq (process-status process) '(exit signal))
(with-current-buffer buffer
(fundamental-mode)
(beginning-of-buffer))))))))))
The hardest part was figuring out when (async-shell-command)
was
finished so that it could apply fundametal-mode for snappier scrolling and
jump to the beginning of the buffer. Thanks to
this code, I was able to
get the desired behavior.
Running (fundamental-mode)
immediately after (async-shell-command)
didn't work well for me, making Emacs unresponsive, probably because
the external command is still altering the buffer. That is why changing
mode is done after the command is completed.
After evaluating the above code, run M-x faster-man
and enjoy (a little
bit) faster man pages :)