;;; sex-mode.el --- Shell EXecute mode / Send to EXterna program ;; ;; Author: Lennart Borgman (lennart O borgman A gmail O com) ;; Created: 2008-06-01T18:41:50+0200 Sun ;; Version: 0.1 ;; Last-Updated: 2008-06-01T20:21:06+0200 Sun ;; URL: ;; Keywords: ;; Compatibility: ;; ;; Features that might be required by this library: ;; ;; None ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;; Commentary: ;; ;; Open files in other programs, but add to recentf-mode etc. ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;; Change log: ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; This program 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 program 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 this program; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth ;; Floor, Boston, MA 02110-1301, USA. ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;; Code: (defcustom sex-open-alist '( "\\.pdf\\'" "\\.doc\\'" ) "Alist of file name patterns to handle. Adding to this list will cause those patterns to be added to to `auto-mode-alist' and `file-name-handler-alist' when `sex-mode' is on. This means that opening those files will create a dummy buffer in Emacs in `sex-file-mode' and an external program is called to handle the file." :type '(repeat regexp) :group 'sex) (defcustom sex-keep-dummy-buffer t "Keep dummy buffer after opening file. See `sex-open-alist'." :type 'boolean :group 'sex) (defvar sex-file-name nil) (make-variable-buffer-local 'sex-file-name) (defun sex-file-handler (operation &rest args) "Handler for `insert-file-contents'." (cond ((eq operation 'insert-file-contents) (unless (= 0 (buffer-size)) (error "Buffer must be empty")) (let* ((name (nth 0 args)) (exists (nth 1 args)) (result (sex-handle-by-external name)) (success (nth 0 result)) (msg (nth 1 result))) (setq buffer-file-name name) (if success (progn (insert "This dummy buffer is used just for opening a file.\n" "The file itself was sent to system for opening.\n\n" "To open the file again click here:\n\n ") (save-excursion (insert-text-button buffer-file-name 'action (lambda (button) (sex-handle-by-external buffer-file-name))))) (insert (propertize "Error\n\n" 'face 'font-lock-warning-face) "Tried to send file\n\n\t" buffer-file-name "\n\nto system but it failed with message:\n" msg)))) ;; Handle any operation we don't know about. (t (let ((inhibit-file-name-handlers (cons 'sex-file-handler (and (eq inhibit-file-name-operation operation) inhibit-file-name-handlers))) (inhibit-file-name-operation operation)) (apply operation args))))) (defun sex-handle-by-external (&optional file) "Give file FILE to external program. Return a list: (SUCCESS MESSAGE) where SUCCESS is non-nil if operation succeeded and MESSAGE is an informational message." (unless file (setq file buffer-file-name)) (cond ((fboundp 'w32-shell-execute) (condition-case err (progn (w32-shell-execute "open" (convert-standard-filename file)) (list t "Sent file to system")) (error (list nil (error-message-string err))))) (t (error "Don't know how to handle the file on your OS yet.")))) (define-derived-mode sex-file-mode nil "External" "Mode for files opened in external programs." (set-keymap-parent (current-local-map) button-buffer-map) (set-buffer-modified-p nil) (setq buffer-read-only t)) (define-minor-mode sex-mode "Open certain files in external programs using shell execute." nil :group 'sex :global t (if sex-mode (progn (dolist (patt sex-open-alist) (add-to-list 'auto-mode-alist (cons patt 'sex-file-mode)) (add-to-list 'file-name-handler-alist (cons patt 'sex-file-handler) t))) ;; Remove from the lists: (dolist (patt sex-open-alist) (setq auto-mode-alist (delete (cons patt 'sex-file-mode) auto-mode-alist)) (setq file-name-handler-alist (delete (cons patt 'sex-file-handler) file-name-handler-alist))))) (provide 'sex-mode) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; sex-mode.el ends here