;;; openwith.el --- Open files with external programs ;; Copyright (C) 2007, 2013 Markus Triska ;; Author: Markus Triska ;; Keywords: files, processes ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; This file is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;; This lets you associate external applications with files so that ;; you can open them via C-x C-f, with RET in dired, etc. ;; Copy openwith.el to your load-path and add to your .emacs: ;; (require 'openwith) ;; (openwith-mode t) ;; To customize associations etc., use: ;; ;; M-x customize-group RET openwith RET ;; ;; To prevent openwith-mode from interfering with attachments when ;; writing a message in Gnus, add the following to your .emacs: ;; ;; (require 'mm-util) ;; (add-to-list 'mm-inhibit-file-name-handlers 'openwith-file-handler) ;;; Code: (defconst openwith-version "0.8g") (defgroup openwith nil "Associate external applications with file name patterns." :group 'files :group 'processes) (defcustom openwith-associations '(("\\.pdf\\'" "acroread" (file)) ("\\.mp3\\'" "xmms" (file)) ("\\.\\(?:mpe?g\\|avi\\|wmv\\)\\'" "mplayer" ("-idx" file)) ("\\.\\(?:jp?g\\|png\\)\\'" "display" (file))) "Associations of file patterns to external programs. File pattern is a regular expression describing the files to associate with a program. The program arguments are a list of strings and symbols and are passed to the program on invocation, where the symbol 'file' is replaced by the file to be opened." :group 'openwith :type '(repeat (list (regexp :tag "Files") (string :tag "Program") (sexp :tag "Parameters")))) (defcustom openwith-confirm-invocation nil "Ask for confirmation before invoking external programs." :group 'openwith :type 'boolean) (defun openwith-file-handler (operation &rest args) "Open file with external program, if an association is configured." (when (and openwith-mode (not (buffer-modified-p)) (zerop (buffer-size))) (let ((assocs openwith-associations) (file (car args)) oa) ;; do not use `dolist' here, since some packages (like cl) ;; temporarily unbind it (while assocs (setq oa (car assocs) assocs (cdr assocs)) (when (save-match-data (string-match (car oa) file)) (let ((params (mapcar (lambda (x) (if (eq x 'file) file x)) (nth 2 oa)))) (when (or (not openwith-confirm-invocation) (y-or-n-p (format "%s %s? " (cadr oa) (mapconcat #'identity params " ")))) (apply #'start-process "openwith-process" nil (cadr oa) params) (kill-buffer nil) ;; inhibit actions that would follow the regular ;; insertion of file contents (let (debug-on-error) (error "Opened %s in external program" (file-name-nondirectory file))))))))) ;; when no association was found, relay the operation to other handlers (let ((inhibit-file-name-handlers (cons 'openwith-file-handler (and (eq inhibit-file-name-operation operation) inhibit-file-name-handlers))) (inhibit-file-name-operation operation)) (apply operation args))) ;;;###autoload (define-minor-mode openwith-mode "Automatically open files with external programs." :lighter "" :global t (if openwith-mode (progn ;; register `openwith-file-handler' for all files (put 'openwith-file-handler 'safe-magic t) (put 'openwith-file-handler 'operations '(insert-file-contents)) (add-to-list 'file-name-handler-alist '("" . openwith-file-handler))) (setq file-name-handler-alist (delete '("" . openwith-file-handler) file-name-handler-alist)))) (provide 'openwith) ;;; openwith.el ends here