Assume you are using a Linux distro.
There are several ways to achieve the effects you want and each of them comes with advantages and disadvantages.
The simplistic way to achieve this is to set org-file-apps
to:
((auto-mode . emacs)
("\\.mm\\'" . default)
("\\.x?html?\\'" . default)
("\\.pdf\\'" . "evince $s"))
The advantage of this approach is that it works and is just a change of variables, which is straightforward. The disadvantage is that you must specify which command to use for the types of file concerned. Another disadvantage is that the evince process is actually a child process of the running Emacs itself and this means the PDF reader has also to be closed when you exit Emacs.
After reading the documentation for org-file-apps
, I am tempted to set it to:
((auto-mode . emacs)
(t . "xdg-open %s") ;; This does NOT work.
("\\.mm\\'" . default)
("\\.x?html?\\'" . default)
("\\.pdf\\'" . default))
The command xdg-open
is used on most Linux distros for opening file with default app. See xdg-open.
The reason why it doesn't work can be answered by this line of code from org-open-file
.
(start-process-shell-command cmd nil cmd)
The function start-process-shell-command
actually executes cmd
and then communicates with it using pty instead of pipe. See the doc for process-connection-type
.
To walk around this, we can, however, use a function instead of a command string for default action.
(defun xdg-open (file link)
(let ((process-connection-type)) ; using pipe instead pty
(start-process
"xdg-open" nil "xdg-open" file)))
And set org-file-apps
to:
((auto-mode . emacs)
(t . xdg-open)
("\\.mm\\'" . default)
("\\.x?html?\\'" . default)
("\\.pdf\\'" . default))
This way, whatever reader launched by xdg-open
will not be a child process of running Emacs. They are independent of each other.
In fact, xdg-open
is a very useful function by its own. You probably want to use M-x xdg-open
or bind it to whatever key you like. To do that, you have to update it to:
(defun xdg-open (file &optional link) ; link is unused
(interactive "fFilename: ")
(let ((process-connection-type)) ; using pipe instead pty
(start-process
"xdg-open" nil "xdg-open"
(expand-file-name file)))) ; maybe unexpanded
Note that we have to expand the filename if we want to use xdg-open
outside of org-open-file
. The reason why previous version don't need to expand is that org-open-file
expands the filename for us.
So far so good. And finally here comes my favorite approach using advising function.
By reading the source code of org-open-file
carefully, we can find that it actually uses find-file-other-window
to open the file as a fallback option. See L8579 of org.el
and L235 of ol.el
.
We can advise the function find-file-other-window
with xdg-find-file
(defined below) and leave the variable org-file-apps
untouched.
(defun xdg-find-file (orig-fun &rest args)
(let* ((filename (car args)))
(if (cl-find-if
(lambda (regexp) (string-match regexp filename))
'("\\.pdf\\'" "\\.docx?\\'"))
(xdg-open filename)
(if (not (file-directory-p directory))
(make-directory directory t))
(apply orig-fun args))))
(advice-add 'find-file-other-window :around 'xdg-find-file)
In fact, we can also advise find-file
around xdg-find-file
so that it becomes Emacs-wide default action for opening PDF and Word file with system default application.
(advice-add 'find-file :around 'xdg-find-file)
The advantage of this approach is that this is an Emacs-wide solution. Not only org-mode
calls find-file
and find-file-other-window
, but also many other Emacs packages relies on these two functions. Now I can even open a PDF with system default app by C-x C-f
. In addition, I can control what kind of files to open with system default app.
To know more about advising function, see (elisp) Advising Functions.
C-h v org-file-apps
? I see((auto-mode . emacs) ("\\.mm\\'" . default) ("\\.x?html?\\'" . default) ("\\.pdf\\'" . "acroread %s"))
org-mode
version 8.2.10. The example works as advertised by opening up the pdf file in my default system-defined application of Skim.app. Please try with Emacs -Q and see if it works correctly. If it works with Emacs -Q, then something in your user configuration has caused the conflict. Recursively bisect your user configuration by commenting stuff out until you find the culprit.((auto-mode . emacs) ("\\.mm\\'" . default) ("\\.x?html?\\'" . default) ("\\.pdf\\'" . default))
emacs -Q
this is the snapshot version. The other question asked about configuration. This is about restoring the default. How would you clarify? (feel free to edit, if you wish)