I'm trying to use Document View in Emacs to read PDFs, but I can't figure out how to make it behave similarly to the 'fit to width' command many PDF readers have. Is there an internal way to do this?
-
5Does `M-x doc-view-fit-width-to-window` (bound to `W` by default in DocView mode) not do what you want? – ChrisGPT was on strike Apr 23 '14 at 11:44
-
1Thanks for asking this - it made me look at what doc-view offered (via "describe-mode") - fit width, fit page, view as text. – Jeffrey DeLeo Apr 23 '14 at 13:42
-
@Chris - That works great, thanks! Is there a hook for when Document View starts up that I can bind this command to? – Koz Ross Apr 23 '14 at 20:32
-
@MrSinister13, unfortunately I can't find a good way to do that. There is `doc-view-mode-hook`, but running `doc-view-fit-width-to-window` from that hook doesn't seem to do anything useful. I'm sure this is possible with more elisp knowledge than I have... – ChrisGPT was on strike Apr 24 '14 at 00:38
4 Answers
The following snippet defines a new minor-mode doc-view-autofit-mode
, which I have activated below using doc-view-mode-hook
. It works for me on Emacs 24.3 on Ubuntu 14.04, even to the point of resizing the zoom when I resize the window!
(There is usually a short resize delay thanks to doc-view-autofit-timer-start
, but I'm happy to live with this.)
I take no credit for the solution; I found this code on the emacs-devel mailing list.
(require 'cl)
;;;; Automatic fitting minor mode
(defcustom doc-view-autofit-timer-start 1.0
"Initial value (seconds) for the timer that delays the fitting when
`doc-view-autofit-fit' is called (Which is when a window
configuration change occurs and a document needs to be fitted)."
:type 'number
:group 'doc-view)
(defcustom doc-view-autofit-timer-inc 0.02
"Value to increase (seconds) the timer (see `doc-view-autofit-timer-start')
by, if there is another window configuration change occuring, before
it runs out."
:type 'number
:group 'doc-view)
(defcustom doc-view-autofit-default-fit 'width
"The fitting type initially used when mode is enabled.
Valid values are: width, height, page."
:type 'symbol
:group 'doc-view)
(defvar doc-view-autofit-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-c W") 'doc-view-autofit-width)
(define-key map (kbd "C-c H") 'doc-view-autofit-height)
(define-key map (kbd "C-c P") 'doc-view-autofit-page)
map)
"Keymap used by `doc-view-autofit-mode'.")
(defun doc-view-autofit-set (type)
"Set autofitting to TYPE for current buffer."
(when doc-view-autofit-mode
(setq doc-view-autofit-type type)
(doc-view-autofit-fit)))
(defun doc-view-autofit-width ()
"Set autofitting to width for current buffer."
(interactive) (doc-view-autofit-set 'width))
(defun doc-view-autofit-height ()
"Set autofitting to height for current buffer."
(interactive) (doc-view-autofit-set 'height))
(defun doc-view-autofit-page ()
"Set autofitting to page for current buffer."
(interactive) (doc-view-autofit-set 'page))
(defun doc-view-autofit-fit ()
"Fits the document in the selected window's buffer
delayed with a timer, so multiple calls in succession
don't cause as much overhead."
(lexical-let
((window (selected-window)))
(if (equal doc-view-autofit-timer nil)
(setq doc-view-autofit-timer
(run-with-timer
doc-view-autofit-timer-start nil
(lambda ()
(if (window-live-p window)
(save-selected-window
(select-window window)
(cancel-timer doc-view-autofit-timer)
(setq doc-view-autofit-timer nil)
(cond
((equal 'width doc-view-autofit-type)
(doc-view-fit-width-to-window))
((equal 'height doc-view-autofit-type)
(doc-view-fit-height-to-window))
((equal 'page doc-view-autofit-type)
(doc-view-fit-page-to-window))))))))
(timer-inc-time doc-view-autofit-timer doc-view-autofit-timer-inc))))
(define-minor-mode doc-view-autofit-mode
"Minor mode for automatic (timer based) fitting in DocView."
:lighter " AFit" :keymap doc-view-autofit-mode-map :group 'doc-view
(when doc-view-autofit-mode
(set (make-local-variable 'doc-view-autofit-type)
doc-view-autofit-default-fit)
(set (make-local-variable 'doc-view-autofit-timer) nil)
(add-hook 'window-configuration-change-hook
'doc-view-autofit-fit nil t)
(doc-view-autofit-fit))
(when (not doc-view-autofit-mode)
(remove-hook 'window-configuration-change-hook
'doc-view-autofit-fit t)
(when doc-view-autofit-timer
(cancel-timer doc-view-autofit-timer)
(setq doc-view-autofit-timer nil))
(setq doc-view-autofit-type nil)))
(add-hook 'doc-view-mode-hook 'doc-view-autofit-mode)

- 127,765
- 105
- 273
- 257
-
Using the above-solution, I added the following two definitions: `(defvar doc-view-autofit-timer nil)` and `(defvar doc-view-autofit-type nil)` – lawlist Jul 12 '14 at 18:29
It works for me:
(add-hook 'doc-view-mode-hook 'doc-view-fit-width-to-window)
Update: It doesn't work correctly if a conversion (to png or something else) is still ongoing (First opening the document). There is alternative, more reliable way, which handles this special case (it doesn't use hook at all but uses advice):
(defadvice doc-view-display (after fit-width activate)
(doc-view-fit-width-to-window))

- 2,340
- 15
- 26
-
Really? What's your Emacs version? I still can't get it to work under Emacs 24.3 on Ubuntu... – ChrisGPT was on strike Apr 26 '14 at 20:15
-
Actually, this seems to work on *redisplay*, e.g. if you `C-c C-c` into edit mode and then back. But it doesn't work for me on initial display. – ChrisGPT was on strike Apr 26 '14 at 21:09
-
2This still gives me the same behaviour: It works on redisplay, but not on initial load. On initial load I get `File mode specification error: (error "Invalid image specification: nil")`. – ChrisGPT was on strike Apr 27 '14 at 02:14
-
Can you enable debug by `M-x toggle-debug-on-error` and show the stack? I got this error when I tried with hook, but with advice I can't reproduce it. Fitting just works on initial load too. – artscan Apr 27 '14 at 02:47
-
Yes, I get [this stack trace](http://pastebin.com/QJsi4Fxe). Using `emacs -Q`, Emacs version 24.3.50.1 on Ubuntu 14.04. – ChrisGPT was on strike Apr 28 '14 at 17:17
-
On Emacs 24 it is recommended to use `advice-add` instead of `defadvise`. Anybody managed to make this work? – krokodil Jan 03 '18 at 18:14
The following is a slight modification of the answer by Chris -- it provides compatibility with functions like find-file-other-window
-- e.g., when the selected-window
is different than the one displaying the *.pdf
file.
(defvar last-displayed-doc-view-buffer nil)
(defun get-last-displayed-doc-view-buffer ()
(setq last-displayed-doc-view-buffer (current-buffer)))
(add-hook 'doc-view-mode-hook 'get-last-displayed-doc-view-buffer)
(defun doc-view-autofit-fit ()
"Fits the document in the selected window's buffer
delayed with a timer, so multiple calls in succession
don't cause as much overhead."
(if (null doc-view-autofit-timer)
(setq doc-view-autofit-timer
(run-with-timer doc-view-autofit-timer-start nil (lambda ()
(let* (
(selected-window
(cond
((eq major-mode 'doc-view-mode)
(selected-window))
(t
(get-buffer-window last-displayed-doc-view-buffer))))
(current-buffer
(cond
((eq major-mode 'doc-view-mode)
(current-buffer))
(t
(get-buffer last-displayed-doc-view-buffer))))
(selected-fit
(when (buffer-live-p (get-buffer current-buffer))
(with-current-buffer (get-buffer current-buffer)
doc-view-autofit-type))) )
(when (window-live-p selected-window)
(with-selected-window selected-window
(when doc-view-autofit-timer (cancel-timer doc-view-autofit-timer))
(setq doc-view-autofit-timer nil)
(cond
((eq 'width selected-fit)
(doc-view-fit-width-to-window))
((eq 'height selected-fit)
(doc-view-fit-height-to-window))
((eq 'page selected-fit)
(doc-view-fit-page-to-window)))))))))
(timer-inc-time doc-view-autofit-timer doc-view-autofit-timer-inc)))
And, as noted in my earlier comment to Chris' answer, the following variables need definitions:
(defvar doc-view-autofit-timer nil)
(defvar doc-view-autofit-type nil)
Because the modification above adds a new function to the doc-view-mode-hook
to obtain the current-buffer
, which is needed for the function doc-view-autofit-fit
, it is necessary to ensure that the latter function is appended to the end of the doc-view-mode-hook
. So the change looks like this -- i.e., we add a t
for the append argument:
(add-hook 'doc-view-mode-hook 'doc-view-autofit-mode t)
Everything else from Chris's answer that has not been superseded by the above modifications remain in effect.
TO DO:
- Create a test to examine each page while scrolling to make certain that the view coincides with the
autofit-type
. Presently, errors occur in page size when dealing with a long*.pdf
file.

- 13,099
- 3
- 49
- 158
Just a note: (require 'cl) is out of date. Since emacs-24.3 it should be
(require ‘cl-lib)

- 11
- 2