52

When I M-x find-file a PDF, it is opened in Emacs. While this is nice, Emacs' PDF viewer lacks many features that I need and I would prefer to open PDFs in an external program instead. How can I configure Emacs to use an external program as the default viewer for PDFs?

7 Answers 7

42

Try openwith. The following code will enable it, and allow you to open PDFs with evince (change to your favorite PDF viewer):

(require 'openwith)
(openwith-mode t)
(setq openwith-associations '(("\\.pdf\\'" "evince" (file))))
5
  • 5
    I'm surprised that a third-party package is needed for something simple as that. But it works, thank you!
    – tmalsburg
    Commented Nov 4, 2014 at 23:28
  • It is not needed (see Drew's answer) but it is a nice and clean way to do it. Note that it will possibly conflict with other programs, like a music reader (mpg123) if you use one.
    – Ehvince
    Commented Nov 5, 2014 at 9:55
  • This solution has problems. It appears that some packages don't like it when you mess with find-file. For instance, sending emails with attached PDFs (via mu4e) causes the attached PDF to be opened in the external editor and sending fails (see here for details).
    – tmalsburg
    Commented Nov 13, 2014 at 5:34
  • 2
    @tmalsburg: have a look at this SO thread discussing the problem with email attachments and a solution in that particular use case.
    – Dan
    Commented Nov 13, 2014 at 11:17
  • I just wrote a bit of code to advise the commands that don't work with openwith-mode to turn it off: see this gist.
    – Omar
    Commented Dec 3, 2014 at 22:21
24

If you want to view PDF with many features (highlighting search, highlighting selection, annotate, content tree), use pdf-tools. As you can see in the demo, I can using Isearch with highlighting. Emacs is now my favourite PDF reader. You can also bookmark specific PDF page by using Bookmark(+).

EDIT: If you use helm and want to use external program, helm already has one in the action menu for opening external file: Open file externally C-c C-x. C-u to choose again. What it does it that it offers a list of all available programs in your system and present you with a nice Helm interface to select from; once you select, Helm remembers it until you run the command with prefix argument C-u to select a new one.

4
  • 4
    +1 I can't thank you enough for mentioning pdf-tools!! AMAZING package. Love it! Your demo is great as well, even though it only scratches the surface of what's possible... :)
    – itsjeyd
    Commented Nov 5, 2014 at 8:38
  • pdf-tools doesn't seem available through standard package managers though, and the install procedure doesn't seem to work with emacs 24.4 :/
    – Clément
    Commented Nov 5, 2014 at 16:07
  • It works for me. But you have to clone the pdf-tools repo and compile and install the C part anywhere your Emacs can see the binary, before installing and using the Emacs Lisp part.
    – Tu Do
    Commented Nov 5, 2014 at 16:12
  • Does pdf-tools allow you to highlight (i.e. in yellow) words and phrases or no? Commented Jun 30, 2015 at 17:31
14

You asked about find-file. In addition to what others (e.g., Dan) say about that, it is worthwhile to also know about opening files using an application associated with the file type (e.g. extension) in option dired-guess-shell-alist-user. And if you use Emacs on MS Windows, then it is worthwhile knowing how to open a file using Windows file associations.

Option dired-guess-shell-alist-user is available after you load standard library dired-x.el. The default association of a PDF file is defined in variable dired-guess-shell-alist-default, and it is program xpdf (available on UNIX and GNU/Linux). Using option dired-guess-shell-alist-user you can, for instance, associate it instead with Adobe Acrobat Reader by adding this association to the alist: ("\.pdf$" . "AcroRd32.exe").

Then you can open a PDF file in Dired just by using !. That provides default programs as "guesses", which you can access by repeating M-n. So ! followed by M-n will give you the shell command AcroRd32.exe if point is on a PDF file name and if that command/program is associated with regexp \.pdf$.

In addition to Dired, you can make use of the file associations in dired-guess-shell-alist-user as a bookmark file handler, that is, have the PDF file association take effect for any bookmarks to PDF files, if you use library Bookmark+. The current value of dired-guess-shell-alist-user is used as the default value of option bmkp-default-handlers-for-file-types, which controls this.

You can think of options dired-guess-shell-alist-user and bmkp-default-handlers-for-file-types as somewhat analogous to auto-mode-alist. But they map file-name patterns to file actions instead of mapping them to buffer modes. And they take effect only when you use certain commands.

If you use MS Windows then you can instead (or also) take advantage of existing Windows file associations when you open a file in Dired or "jump" to a bookmark. For this you need library w32-browser.el.

For Dired, you also need library Dired+ - see Using Windows File Associations in Dired. For bookmarks, you also need Bookmark+ - see Bookmarking Files You Cannot Visit With Emacs and Opening Bookmarks Using Windows File Associations.

3

I'm using runner. Here is an excerpt of my configuration file

    (defun my:open-file-with-dired (file)
      "Ask dired how it would open FILE.
This code is useful if dired is well configured to open files
with external applications. I recommend using the `runner`
package to do so."
      (use-package dired-aux)
      (dired-do-async-shell-command
       (dired-guess-shell-command (format  "Open %s " file) (list file))
       0
       (list file)))

    (add-to-list 'org-file-apps '(t . (my:open-file-with-dired file)))
    (add-to-list 'org-file-apps '("\\.png\\'" . default))
2

What about that one?

W runs the command browse-url-of-dired-file (found in dired-mode-map), which is
an autoloaded interactive compiled Lisp function in ‘browse-url.el’.

It is bound to W, <normal-state> W.

(browse-url-of-dired-file)

  Probably introduced at or before Emacs version 26.1.

In Dired, ask a WWW browser to display the file named on this line.
1

This is what I put in my init file:

(setq dired-guess-shell-alist-user '(("\\.pdf$" "nohup xdg-open * </dev/null >/dev/null 2>&1 &")))

It uses dired-guess-shell-alist-user as suggested in the answer by Drew and xdg-open as suggested by Lei Zhao. So when I hit ! in dired it will open the pdf with my pdf viewer picked by xdg-open (my OS is Ubuntu). Furthermore the stdin, stdout and stderr is redirected. This has the effect that no strange nohup.out will be created. This is according to the thorough answer given by Mark Reed on how to avoid nohup.out.
Lastly to make it work also add

(require 'dired-x)

or something comparable to your init.el. The necessity to load dired-x is mentioned by Sean Allred in responde to a similar question.

The code above only works for dired, so find-file will not work. Furthermore, it also splits the dired window in half giving a short message, which is a little bit annoying.

I added this answer, because I found the * notation helpful, which is mentioned in the online documentation. The asterisk notation allows one to wrap the command in nohup and & to let it run in background and not terminate when the terminal is closed.

Adding further file extensions besides pdf is simple:

(setq dired-guess-shell-alist-user '(("\\.pdf$" "nohup xdg-open * </dev/null >/dev/null 2>&1 &")
                                     ("\\.jpg$" "nohup xdg-open * </dev/null >/dev/null 2>&1 &")
                                     ("\\.ods$" "nohup xdg-open * </dev/null >/dev/null 2>&1 &")))

Edit 1: Added input and output redirection to nohup
Edit 2: Add hint to (require 'dired-x) (sry for bumping old thread, last edit I promise)

0

My way to achieve this without any plugins is the following. I run Emacs 25.3 under Ubuntu 16.04 LTS. If your OS is macOS or Windows, you definitely need to change the the first function xdg-open defined here. I found this link very helpful as a starting point.

(defun xdg-open (filename)
  (interactive "fFilename: ")
  (let ((process-connection-type))
    (start-process "" nil "xdg-open" (expand-file-name filename))))

(defun find-file-auto (orig-fun &rest args)
  (let ((filename (car args)))
    (if (cl-find-if
         (lambda (regexp) (string-match regexp filename))
         '("\\.pdf\\'" "\\.docx?\\'"))
        (xdg-open filename)
      (apply orig-fun args))))

(advice-add 'find-file :around 'find-file-auto)

After the above code is loaded, when you press C-x C-f for PDF and word file, it will automatically open the file using system default app.

I really like the advice mechanism provided by Emacs, see (elisp) Advising Functions. By advising existent function in a compatible way, I avoid re-binding common keys like C-x C-f to new function.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.