⬆️ ⬇️

Open files in external applications

Emacs has a cool learning curtain, but the further you go, the more you want to do everything you can and cannot do. In particular, it has a large number of tools for navigating the file system.

I, for example, use Dired mode, ido, Org mode and bookmarks. But there is a problem with opening files in external applications: pdf in evince, avi in ​​mplayer, etc. And I want to ask these links in one place. Emacs would not be Emacs if it didn’t allow me to do some dirty hack =)



Application associations with file types will be defined as a list of pairs in which the first element is a string, separated by a space of extensions, and the second is a command to launch the application:



(defvar command-list

'(("jpg jpeg png bmp" .

"gqview")

("pdf djvu ps" .

"evince")

("html htm" .

"firefox -new-tab")

("ogv mpg mpeg avi flv

VOB wmv mp4 mov mkv divx

ogm m4v asf rmvb" .

"mplayer -fs")

("doc odf odt rtf" .

"ooffice")))



From a line of extensions we will make a regular session:



(defun build-re (str)

(let ((re "\\.\\(")

(ext-list (split-string str)))

(dotimes (n (- (length ext-list) 1))

(setq re (concat re (nth n ext-list) "$\\|")))

(setq re (concat re (car (last ext-list)) "$\\)$"))

re))



Write a function that gets the path to the file

')

(defun try-open-external (filename)

(let ((success nil))

;; ,

(dolist (command command-list)

(let ((cmd (cdr command))

;; ,

(re (build-re (car command))))

;; .

(when (string-match re filename)

;; ,

(shell-command-to-string (concat cmd

" "

(shell-quote-argument filename)

" &> /dev/null &"))

(setq success t))))

;; .

success))



Now we need to force Emacs to run our function when trying to open a file. The documentation tells us that functions like find-file use find-file-noselect.



Therefore, we will keep the system function



(fset 'old-find-file-noselect (symbol-function 'find-file-noselect))



and redefine it so that it tries to open the file in an external program,



(defun find-file-noselect (filename &optional nowarn rawfile wildcards)

(if (try-open-external filename)

nil

;; .

(old-find-file-noselect filename nowarn rawfile wildcards)))



For Org mode, we write a small function so that when opening links

switching to another window was only for files opened inside Emacs



(defun my-org-find-file (file)

(when (not (try-open-external file))

(find-file-other-window file)))



and we will use it for all types of files



(org-file-apps (quote ((".*" my-org-find-file file))))





So far there have been no special problems with this, although, for example, launching external applications via tramp does not work, but it seems to be right.



Download the code.



Any criticism and advice, as they say, well.

Source: https://habr.com/ru/post/47524/



All Articles