Opening files with default Windows application from within emacs
Asked Answered
E

9

12

I'm trying to tweak the dired-find-file function in emacs on Windows XP so that when I open (say) a pdf file from dired it fires up a copy of Acrobat Reader and opens that file with it, instead of opening it within emacs. But I can't work out what variant on shell-command/call-process to use. Here's what I have so far:

(defadvice dired-find-file (around dired-find-file-external (filename &optional wildcards))
  "Open non-text files with an appropriate external program."
  (if (string= ".pdf" (substring filename (- (length filename) 4))) ; obviously I'll replace this with something more general/robust
    (shell-command filename) ;; what should go here?
    (ad-do-it)))

(ad-activate 'dired-find-file)

I know I could hard-code it to start Acrobat Reader by giving it the location of the .exe file. But I'd rather have something which requires less searching from me and which won't break when default applications move/change. What should I use?

Endorsee answered 17/2, 2010 at 20:54 Comment(0)
H
8
  1. Evaluate the following elisp
  2. Run dired (M-x dired)
  3. Browse to directory and file
  4. With point on file, pressing F3 will open the file based on the windows extension.

    (defun w32-browser (doc) (w32-shell-execute 1 doc))

    (eval-after-load "dired" '(define-key dired-mode-map [f3] (lambda () (interactive) (w32-browser (dired-replace-in-string "/" "\\" (dired-get-filename))))))

Hawaiian answered 18/2, 2010 at 3:42 Comment(2)
Not keen on eval-after-load, but +1 for w32-shell-execute - it's clearly the Right Way To Do It.Endorsee
Whye it says Defining kbd macro... when I press ``F3`Griddle
T
9

To extend on the 'org-open-file' proposal:

(defun my-dired-find-file (&optional prefix)
    (interactive "P")
    (if prefix
        (org-open-file (dired-get-file-for-visit) 'system)
      (dired-find-file)))

(define-key dired-mode-map "\r" 'my-dired-find-file)

Will let you open a file externally with `C-u RET'.

found at http://lists.gnu.org/archive/html/bug-gnu-emacs/2012-11/msg01069.html

Tineid answered 14/12, 2012 at 7:42 Comment(0)
H
8
  1. Evaluate the following elisp
  2. Run dired (M-x dired)
  3. Browse to directory and file
  4. With point on file, pressing F3 will open the file based on the windows extension.

    (defun w32-browser (doc) (w32-shell-execute 1 doc))

    (eval-after-load "dired" '(define-key dired-mode-map [f3] (lambda () (interactive) (w32-browser (dired-replace-in-string "/" "\\" (dired-get-filename))))))

Hawaiian answered 18/2, 2010 at 3:42 Comment(2)
Not keen on eval-after-load, but +1 for w32-shell-execute - it's clearly the Right Way To Do It.Endorsee
Whye it says Defining kbd macro... when I press ``F3`Griddle
V
4

Use Dired+ for this, along with w32-browser.el

  • C-RET opens the current-line's file using its Windows file-association application.

  • M-RET opens Windows Explorer to the file or folder

  • ^, when in a root directory (e.g. C:\), moves up to a Dired-like list of all Windows drives (local and remote).

The commands for the first two are available from w32-browser.el. (Dired+ binds them to those keys.) The command for the third is from Dired+.

Viridian answered 21/8, 2011 at 21:18 Comment(2)
But the minibuffer says the M-Ret is not definedGriddle
@ZhaoGang: Thanks. Corrected. Forgot that the first two commands are defined in w32-browser.el.Viridian
E
3

I found this terrific web page via google, which let me to a technique using RunDll that works. I'm putting it up here in case anyone else is curious.

Here is the key piece of code, which opens filename using the appropriate application:

(shell-command (concat "rundll32 shell32,ShellExec_RunDLL " (shell-quote-argument filename)))

And here is my full solution. (Note that dired-find-file is just a wrapper round find-file which doesn't know the filename, so that you have to advise find-file rather than dired-find-file as in the question. If you don't want the behaviour for find-file you will probably need to rewrite dired-find-file or write more complicated advice.)

(defun open-externally (filename)
  (shell-command (concat "rundll32 shell32,ShellExec_RunDLL " (shell-quote-argument filename))))

(defun is-file-type? (filename type)
  (string= type (substring filename (- (length filename) (length type)))))

(defun should-open-externally? (filename)
  (let ((file-types '(".pdf" ".doc" ".xls")))
    (member t (mapcar #'(lambda (type) (is-file-type? filename type)) file-types))))

(defadvice find-file (around find-file-external-file-advice (filename &optional wildcards))
  "Open non-emacs files with an appropriate external program"
  (if (should-open-externally? filename)
      (open-externally filename)
    ad-do-it))

(ad-activate 'find-file)
Endorsee answered 17/2, 2010 at 22:10 Comment(0)
F
2

I have this in my .emacs:

(setq dired-guess-shell-alist-user
  (list
    (list "\\.*$" "cmd /k")
  ))

This will open the file using cmd.exe which will use whatever program is associated with the file extension. Tested to work on Windows 8 and GNU Emacs 24.2.1.

Foehn answered 30/3, 2013 at 22:47 Comment(1)
I'm testing (setq dired-guess-shell-alist-user '((".*" (concat "start " "\"" file "\"")))) at the moment. (I encountered filenames with spaces.)Winifield
E
1

Tom Smith's answer is nice, but you can also just run the program "start" with the filename as an argument.

(shell-command (concat "start " (shell-quote-argument filename)))
Embouchure answered 18/2, 2010 at 1:40 Comment(2)
Are you sure? When I've tried this it doesn't work - I just get an empty command prompt window.Endorsee
@Tom: That makes sense, since the first quoted argument to start is used as the window title.Fernandez
C
1

I'd use (w32-shell-execute "open" file-name).

In fact, in my init file I have:

(defun open-externally (file-name)
  (interactive "fOpen externally: ")
  (let ((process-connection-type nil))
     (start-process "open-externally" nil
                    "xdg-open" file-name)))

(when (eq window-system 'w32)
  (defun open-externally (file-name)
    (interactive "fOpen externally: ")
    (w32-shell-execute "open" file-name)))

Which defines a command that (may be used interactively and) opens a file with the default application according to xdg-open and then, if I'm actually on Windows, redefines that command appropriately.

Coben answered 20/11, 2015 at 22:0 Comment(0)
K
0

org-open-file is a system independent external opener. See org-file-apps for how to customize it further.

Khano answered 30/1, 2012 at 19:57 Comment(0)
Q
0

Extending @tom-smith's answer, here is something that I validated and just works on Windows (inspired from @Tom-smith and xahlee blogpost.

Add this snippet to your ~/.emacs.d/init.el:

;;; Open file types with default Windows apps
;;; -------------------------------------------------------------------
(defun open-externally (filename)
  (shell-command (format "%s" (shell-quote-argument filename))))

(defun is-file-type? (filename type)
  (string= type (substring filename (- (length filename) (length type)))))

;; => change this to include more file types <=
(defun should-open-externally? (filename)
  (let ((file-types '(".pdf" ".doc" ".xls" ".html")))
    (member t (mapcar #'(lambda (type) (is-file-type? filename type)) file-types))))

(defadvice find-file (around find-file-external-file-advice (filename &optional wildcards))
  "Open non-emacs files with an appropriate external program"
   (if (should-open-externally? filename)
      (open-externally filename)
     ad-do-it))

(ad-activate 'find-file)
;;; -------------------------------------------------------------------
Quadragesima answered 24/3, 2022 at 17:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.